34270 lines
977 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* elFinder - file manager for web
* Version 2.1.43 (2018-11-24)
* http://elfinder.org
*
* Copyright 2009-2018, Studio 42
* Licensed under a 3-clauses BSD license
*/
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery','jquery-ui'], factory);
} else if (typeof exports !== 'undefined') {
// CommonJS
var $, ui;
try {
$ = require('jquery');
ui = require('jquery-ui');
} catch (e) {}
module.exports = factory($, ui);
} else {
// Browser globals (Note: root is window)
factory(root.jQuery, root.jQuery.ui, true);
}
}(this, function($, _ui, toGlobal) {
toGlobal = toGlobal || false;
/*
* File: /js/elFinder.js
*/
/**
* @class elFinder - file manager for web
*
* @author Dmitry (dio) Levashov
**/
var elFinder = function(elm, opts, bootCallback) {
//this.time('load');
var self = this,
/**
* Objects array of jQuery.Deferred that calls before elFinder boot up
*
* @type Array
*/
dfrdsBeforeBootup = [],
/**
* Plugin name to check for conflicts with bootstrap etc
*
* @type Array
**/
conflictChecks = ['button', 'tooltip'],
/**
* Node on which elfinder creating
*
* @type jQuery
**/
node = $(elm),
/**
* Object of events originally registered in this node
*
* @type Object
*/
prevEvents = $.extend(true, {}, $._data(node.get(0), 'events')),
/**
* Store node contents.
*
* @see this.destroy
* @type jQuery
**/
prevContent = $('<div/>').append(node.contents()).attr('class', node.attr('class') || '').attr('style', node.attr('style') || ''),
/**
* Instance ID. Required to get/set cookie
*
* @type String
**/
id = node.attr('id') || '',
/**
* Events namespace
*
* @type String
**/
namespace = 'elfinder-' + (id ? id : Math.random().toString().substr(2, 7)),
/**
* Mousedown event
*
* @type String
**/
mousedown = 'mousedown.'+namespace,
/**
* Keydown event
*
* @type String
**/
keydown = 'keydown.'+namespace,
/**
* Keypress event
*
* @type String
**/
keypress = 'keypress.'+namespace,
/**
* Keypup event
*
* @type String
**/
keyup = 'keyup.'+namespace,
/**
* Is shortcuts/commands enabled
*
* @type Boolean
**/
enabled = false,
/**
* Store enabled value before ajax request
*
* @type Boolean
**/
prevEnabled = false,
/**
* List of build-in events which mapped into methods with same names
*
* @type Array
**/
events = ['enable', 'disable', 'load', 'open', 'reload', 'select', 'add', 'remove', 'change', 'dblclick', 'getfile', 'lockfiles', 'unlockfiles', 'selectfiles', 'unselectfiles', 'dragstart', 'dragstop', 'search', 'searchend', 'viewchange'],
/**
* Rules to validate data from backend
*
* @type Object
**/
rules = {},
/**
* Current working directory hash
*
* @type String
**/
cwd = '',
/**
* Current working directory options default
*
* @type Object
**/
cwdOptionsDefault = {
path : '',
url : '',
tmbUrl : '',
disabled : [],
separator : '/',
archives : [],
extract : [],
copyOverwrite : true,
uploadOverwrite : true,
uploadMaxSize : 0,
jpgQuality : 100,
tmbCrop : false,
tmb : false // old API
},
/**
* Current working directory options
*
* @type Object
**/
cwdOptions = {},
/**
* Files/dirs cache
*
* @type Object
**/
files = {},
/**
* Hidden Files/dirs cache
*
* @type Object
**/
hiddenFiles = {},
/**
* Files/dirs hash cache of each dirs
*
* @type Object
**/
ownFiles = {},
/**
* Selected files hashes
*
* @type Array
**/
selected = [],
/**
* Events listeners
*
* @type Object
**/
listeners = {},
/**
* Shortcuts
*
* @type Object
**/
shortcuts = {},
/**
* Buffer for copied files
*
* @type Array
**/
clipboard = [],
/**
* Copied/cuted files hashes
* Prevent from remove its from cache.
* Required for dispaly correct files names in error messages
*
* @type Object
**/
remember = {},
/**
* Queue for 'open' requests
*
* @type Array
**/
queue = [],
/**
* Queue for only cwd requests e.g. `tmb`
*
* @type Array
**/
cwdQueue = [],
/**
* Commands prototype
*
* @type Object
**/
base = new self.command(self),
/**
* elFinder node width
*
* @type String
* @default "auto"
**/
width = 'auto',
/**
* elFinder node height
* Number: pixcel or String: Number + "%"
*
* @type Number | String
* @default 400
**/
height = 400,
/**
* Base node object or selector
* Element which is the reference of the height percentage
*
* @type Object|String
* @default null | $(window) (if height is percentage)
**/
heightBase = null,
/**
* MIME type list(Associative array) handled as a text file
*
* @type Object|null
*/
textMimes = null,
/**
* elfinder path for sound played on remove
* @type String
* @default ./sounds/
**/
soundPath = 'sounds/',
/**
* JSON.stringify of previous fm.sorters
* @type String
*/
prevSorterStr = '',
/**
* Map table of file extention to MIME-Type
* @type Object
*/
extToMimeTable,
beeper = $(document.createElement('audio')).hide().appendTo('body')[0],
syncInterval,
autoSyncStop = 0,
uiCmdMapPrev = '',
gcJobRes = null,
open = function(data) {
// NOTES: Do not touch data object
var volumeid, contextmenu, emptyDirs = {}, stayDirs = {},
rmClass, hashes, calc, gc, collapsed, prevcwd, sorterStr;
if (self.api >= 2.1) {
// support volume driver option `uiCmdMap`
self.commandMap = (data.options.uiCmdMap && Object.keys(data.options.uiCmdMap).length)? data.options.uiCmdMap : {};
if (uiCmdMapPrev !== JSON.stringify(self.commandMap)) {
uiCmdMapPrev = JSON.stringify(self.commandMap);
}
} else {
self.options.sync = 0;
}
if (data.init) {
// init - reset cache
files = {};
ownFiles = {};
} else {
// remove only files from prev cwd
// and collapsed directory (included 100+ directories) to empty for perfomance tune in DnD
prevcwd = cwd;
rmClass = 'elfinder-subtree-loaded ' + self.res('class', 'navexpand');
collapsed = self.res('class', 'navcollapse');
hashes = Object.keys(files);
calc = function(i) {
if (!files[i]) {
return true;
}
var isDir = (files[i].mime === 'directory'),
phash = files[i].phash,
pnav;
if (
(!isDir
|| emptyDirs[phash]
|| (!stayDirs[phash]
&& $('#'+self.navHash2Id(files[i].hash)).is(':hidden')
&& $('#'+self.navHash2Id(phash)).next('.elfinder-navbar-subtree').children().length > 100
)
)
&& (isDir || phash !== cwd)
&& ! remember[i]
) {
if (isDir && !emptyDirs[phash]) {
emptyDirs[phash] = true;
$('#'+self.navHash2Id(phash))
.removeClass(rmClass)
.next('.elfinder-navbar-subtree').empty();
}
deleteCache(files[i]);
} else if (isDir) {
stayDirs[phash] = true;
}
};
gc = function() {
if (hashes.length) {
gcJobRes && gcJobRes._abort();
gcJobRes = self.asyncJob(calc, hashes, {
interval : 20,
numPerOnce : 100
}).done(function() {
var hd = self.storage('hide') || {items: {}};
if (Object.keys(hiddenFiles).length) {
$.each(hiddenFiles, function(h) {
if (!hd.items[h]) {
delete hiddenFiles[h];
}
});
}
});
}
};
self.trigger('filesgc').one('filesgc', function() {
hashes = [];
});
self.one('opendone', function() {
if (prevcwd !== cwd) {
if (! node.data('lazycnt')) {
gc();
} else {
self.one('lazydone', gc);
}
}
});
}
self.sorters = {};
cwd = data.cwd.hash;
cache(data.files);
if (!files[cwd]) {
cache([data.cwd]);
}
// trigger event 'sorterupdate'
sorterStr = JSON.stringify(self.sorters);
if (prevSorterStr !== sorterStr) {
self.trigger('sorterupdate');
prevSorterStr = sorterStr;
}
self.lastDir(cwd);
self.autoSync();
},
/**
* Store info about files/dirs in "files" object.
*
* @param Array files
* @param String data type
* @return void
**/
cache = function(data, type) {
var defsorter = { name: true, perm: true, date: true, size: true, kind: true },
sorterChk = !self.sorters._checked,
l = data.length,
setSorter = function(file) {
var f = file || {},
sorters = [];
$.each(self.sortRules, function(key) {
if (defsorter[key] || typeof f[key] !== 'undefined' || (key === 'mode' && typeof f.perm !== 'undefined')) {
sorters.push(key);
}
});
self.sorters = self.arrayFlip(sorters, true);
self.sorters._checked = true;
},
keeps = ['sizeInfo'],
changedParents = {},
hideData = self.storage('hide') || {},
hides = hideData.items || {},
f, i, keepProp, parents, hidden;
for (i = 0; i < l; i++) {
f = Object.assign({}, data[i]);
hidden = (!hideData.show && hides[f.hash])? true : false;
if (f.name && f.hash && f.mime) {
if (!hidden) {
if (sorterChk && f.phash === cwd) {
setSorter(f);
sorterChk = false;
}
if (f.phash && (type === 'add' || type === 'change')) {
if (parents = self.parents(f.phash)) {
$.each(parents, function() {
changedParents[this] = true;
});
}
}
}
if (files[f.hash]) {
$.each(keeps, function() {
if(files[f.hash][this] && ! f[this]) {
f[this] = files[f.hash][this];
}
});
if (f.sizeInfo && !f.size) {
f.size = f.sizeInfo.size;
}
deleteCache(files[f.hash], true);
}
if (hides[f.hash]) {
hiddenFiles[f.hash] = f;
}
if (hidden) {
l--;
data.splice(i--, 1);
} else {
files[f.hash] = f;
if (f.mime === 'directory' && !ownFiles[f.hash]) {
ownFiles[f.hash] = {};
}
if (f.phash) {
if (!ownFiles[f.phash]) {
ownFiles[f.phash] = {};
}
ownFiles[f.phash][f.hash] = true;
}
}
}
}
// delete sizeInfo cache
$.each(Object.keys(changedParents), function() {
var target = files[this];
if (target && target.sizeInfo) {
delete target.sizeInfo;
}
});
// for empty folder
sorterChk && setSorter();
},
/**
* Delete file object from files caches
*
* @param Array removed hashes
* @return void
*/
remove = function(removed) {
var l = removed.length,
roots = {},
rm = function(hash) {
var file = files[hash], i;
if (file) {
if (file.mime === 'directory') {
if (roots[hash]) {
delete self.roots[roots[hash]];
}
// restore stats of deleted root parent directory
$.each(self.leafRoots, function(phash, roots) {
var idx, pdir;
if ((idx = $.inArray(hash, roots))!== -1) {
if (roots.length === 1) {
if ((pdir = Object.assign({}, files[phash])) && pdir._realStats) {
$.each(pdir._realStats, function(k, v) {
pdir[k] = v;
});
remove(files[phash]._realStats);
self.change({ changed: [pdir] });
}
delete self.leafRoots[phash];
} else {
self.leafRoots[phash].splice(idx, 1);
}
}
});
if (self.searchStatus.state < 2) {
$.each(files, function(h, f) {
f.phash == hash && rm(h);
});
}
}
if (file.phash) {
if (parents = self.parents(file.phash)) {
$.each(parents, function() {
changedParents[this] = true;
});
}
}
deleteCache(files[hash]);
}
},
changedParents = {},
parents;
$.each(self.roots, function(k, v) {
roots[v] = k;
});
while (l--) {
rm(removed[l]);
}
// delete sizeInfo cache
$.each(Object.keys(changedParents), function() {
var target = files[this];
if (target && target.sizeInfo) {
delete target.sizeInfo;
}
});
},
/**
* Update file object in files caches
*
* @param Array changed file objects
* @return void
*/
change = function(changed) {
$.each(changed, function(i, file) {
var hash = file.hash;
if (files[hash]) {
$.each(Object.keys(files[hash]), function(i, v){
if (typeof file[v] === 'undefined') {
delete files[hash][v];
}
});
}
files[hash] = files[hash] ? Object.assign(files[hash], file) : file;
});
},
/**
* Delete cache data of files, ownFiles and self.optionsByHashes
*
* @param Object file
* @param Boolean update
* @return void
*/
deleteCache = function(file, update) {
var hash = file.hash,
phash = file.phash;
if (phash && ownFiles[phash]) {
delete ownFiles[phash][hash];
}
if (!update) {
ownFiles[hash] && delete ownFiles[hash];
self.optionsByHashes[hash] && delete self.optionsByHashes[hash];
}
delete files[hash];
},
/**
* Maximum number of concurrent connections on request
*
* @type Number
*/
requestMaxConn,
/**
* Current number of connections
*
* @type Number
*/
requestCnt = 0,
/**
* Queue waiting for connection
*
* @type Array
*/
requestQueue = [],
/**
* Flag to cancel the `open` command waiting for connection
*
* @type Boolean
*/
requestQueueSkipOpen = false,
/**
* Exec shortcut
*
* @param jQuery.Event keydown/keypress event
* @return void
*/
execShortcut = function(e) {
var code = e.keyCode,
ctrlKey = !!(e.ctrlKey || e.metaKey),
isMousedown = e.type === 'mousedown',
ddm;
!isMousedown && (self.keyState.keyCode = code);
self.keyState.ctrlKey = ctrlKey;
self.keyState.shiftKey = e.shiftKey;
self.keyState.metaKey = e.metaKey;
self.keyState.altKey = e.altKey;
if (isMousedown) {
return;
} else if (e.type === 'keyup') {
self.keyState.keyCode = null;
return;
}
if (enabled) {
$.each(shortcuts, function(i, shortcut) {
if (shortcut.type == e.type
&& shortcut.keyCode == code
&& shortcut.shiftKey == e.shiftKey
&& shortcut.ctrlKey == ctrlKey
&& shortcut.altKey == e.altKey) {
e.preventDefault();
e.stopPropagation();
shortcut.callback(e, self);
self.debug('shortcut-exec', i+' : '+shortcut.description);
}
});
// prevent tab out of elfinder
if (code == $.ui.keyCode.TAB && !$(e.target).is(':input')) {
e.preventDefault();
}
// cancel any actions by [Esc] key
if (e.type === 'keydown' && code == $.ui.keyCode.ESCAPE) {
// copy or cut
if (! node.find('.ui-widget:visible').length) {
self.clipboard().length && self.clipboard([]);
}
// dragging
if ($.ui.ddmanager) {
ddm = $.ui.ddmanager.current;
ddm && ddm.helper && ddm.cancel();
}
// button menus
self.toHide(node.find('.ui-widget.elfinder-button-menu.elfinder-frontmost:visible'));
// trigger keydownEsc
self.trigger('keydownEsc', e);
}
}
},
date = new Date(),
utc,
i18n,
inFrame = (window.parent !== window),
parentIframe = (function() {
var pifm, ifms;
if (inFrame) {
try {
ifms = $('iframe', window.parent.document);
if (ifms.length) {
$.each(ifms, function(i, ifm) {
if (ifm.contentWindow === window) {
pifm = $(ifm);
return false;
}
});
}
} catch(e) {}
}
return pifm;
})(),
/**
* elFinder boot up function
*
* @type Function
*/
bootUp,
/**
* Original function of XMLHttpRequest.prototype.send
*
* @type Function
*/
savedXhrSend;
// opts must be an object
if (!opts) {
opts = {};
}
// set UA.Angle, UA.Rotated for mobile devices
if (self.UA.Mobile) {
$(window).on('orientationchange.'+namespace, function() {
var a = ((screen && screen.orientation && screen.orientation.angle) || window.orientation || 0) + 0;
if (a === -90) {
a = 270;
}
self.UA.Angle = a;
self.UA.Rotated = a % 180 === 0? false : true;
}).trigger('orientationchange.'+namespace);
}
// check opt.bootCallback
if (opts.bootCallback && typeof opts.bootCallback === 'function') {
(function() {
var func = bootCallback,
opFunc = opts.bootCallback;
bootCallback = function(fm, extraObj) {
func && typeof func === 'function' && func.call(this, fm, extraObj);
opFunc.call(this, fm, extraObj);
};
})();
}
delete opts.bootCallback;
/**
* Protocol version
*
* @type String
**/
this.api = null;
/**
* elFinder use new api
*
* @type Boolean
**/
this.newAPI = false;
/**
* elFinder use old api
*
* @type Boolean
**/
this.oldAPI = false;
/**
* Net drivers names
*
* @type Array
**/
this.netDrivers = [];
/**
* Base URL of elfFinder library starting from Manager HTML
*
* @type String
*/
this.baseUrl = '';
/**
* Base URL of i18n js files
* baseUrl + "js/i18n/" when empty value
*
* @type String
*/
this.i18nBaseUrl = '';
/**
* Is elFinder CSS loaded
*
* @type Boolean
*/
this.cssloaded = false;
/**
* Current theme object
*
* @type Object|Null
*/
this.theme = null;
this.mimesCanMakeEmpty = {};
/**
* Callback function at boot up that option specified at elFinder starting
*
* @type Function
*/
this.bootCallback;
/**
* ID. Required to create unique cookie name
*
* @type String
**/
this.id = id;
/**
* Method to store/fetch data
*
* @type Function
**/
this.storage = (function() {
try {
if ('localStorage' in window && window['localStorage'] !== null) {
if (self.UA.Safari) {
// check for Mac/iOS safari private browsing mode
window.localStorage.setItem('elfstoragecheck', 1);
window.localStorage.removeItem('elfstoragecheck');
}
return self.localStorage;
} else {
return self.cookie;
}
} catch (e) {
return self.cookie;
}
})();
/**
* Configuration options
*
* @type Object
**/
//this.options = $.extend(true, {}, this._options, opts);
this.options = Object.assign({}, this._options);
// for old type configuration
if (opts.uiOptions) {
if (opts.uiOptions.toolbar && Array.isArray(opts.uiOptions.toolbar)) {
if ($.isPlainObject(opts.uiOptions.toolbar[opts.uiOptions.toolbar.length - 1])) {
self.options.uiOptions.toolbarExtra = Object.assign(self.options.uiOptions.toolbarExtra || {}, opts.uiOptions.toolbar.pop());
}
}
}
// Overwrite if opts value is an array
(function() {
var arrOv = function(obj, base) {
if ($.isPlainObject(obj)) {
$.each(obj, function(k, v) {
if ($.isPlainObject(v)) {
if (!base[k]) {
base[k] = {};
}
arrOv(v, base[k]);
} else {
base[k] = v;
}
});
}
};
arrOv(opts, self.options);
})();
// join toolbarExtra to toolbar
this.options.uiOptions.toolbar.push(this.options.uiOptions.toolbarExtra);
delete this.options.uiOptions.toolbarExtra;
// set fm.baseUrl
this.baseUrl = (function() {
var myTag, myCss, base, baseUrl;
if (self.options.baseUrl) {
return self.options.baseUrl;
} else {
baseUrl = '';
//myTag = $('head > script[src$="js/elfinder.min.js"],script[src$="js/elfinder.full.js"]:first');
myTag = null;
$('head > script').each(function() {
if (this.src && this.src.match(/js\/elfinder(?:-[a-z0-9_-]+)?\.(?:min|full)\.js$/i)) {
myTag = $(this);
return false;
}
});
if (myTag) {
myCss = $('head > link[href$="css/elfinder.min.css"],link[href$="css/elfinder.full.css"]:first').length;
if (! myCss) {
// to request CSS auto loading
self.cssloaded = null;
}
baseUrl = myTag.attr('src').replace(/js\/[^\/]+$/, '');
if (! baseUrl.match(/^(https?\/\/|\/)/)) {
// check <base> tag
if (base = $('head > base[href]').attr('href')) {
baseUrl = base.replace(/\/$/, '') + '/' + baseUrl;
}
}
}
if (baseUrl !== '') {
self.options.baseUrl = baseUrl;
} else {
if (! self.options.baseUrl) {
self.options.baseUrl = './';
}
baseUrl = self.options.baseUrl;
}
return baseUrl;
}
})();
this.i18nBaseUrl = (this.options.i18nBaseUrl || this.baseUrl + 'js/i18n').replace(/\/$/, '') + '/';
// set dispInlineRegex
cwdOptionsDefault['dispInlineRegex'] = this.options.dispInlineRegex;
// auto load required CSS
if (this.options.cssAutoLoad) {
(function() {
var baseUrl = self.baseUrl;
if (self.cssloaded === null) {
// hide elFinder node while css loading
node.data('cssautoloadHide', $('<style>.elfinder{visibility:hidden;overflow:hidden}</style>'));
$('head').append(node.data('cssautoloadHide'));
// load CSS
self.loadCss([baseUrl+'css/elfinder.min.css', baseUrl+'css/theme.css'], {
dfd: $.Deferred().always(function() {
if (node.data('cssautoloadHide')) {
node.data('cssautoloadHide').remove();
node.removeData('cssautoloadHide');
}
}).done(function() {
if (!self.cssloaded) {
self.cssloaded = true;
self.trigger('cssloaded');
}
}).fail(function() {
self.cssloaded = false;
self.error(['errRead', 'CSS (elfinder or theme)']);
})
});
// additional CSS files
if (Array.isArray(self.options.cssAutoLoad)) {
self.loadCss(self.options.cssAutoLoad);
}
}
self.options.cssAutoLoad = false;
})();
}
// load theme if exists
self.changeTheme(self.storage('theme') || self.options.theme);
/**
* Volume option to set the properties of the root Stat
*
* @type Object
*/
this.optionProperties = {
icon: void(0),
csscls: void(0),
tmbUrl: void(0),
uiCmdMap: {},
netkey: void(0),
disabled: []
};
if (! inFrame && ! this.options.enableAlways && $('body').children().length === 2) { // only node and beeper
this.options.enableAlways = true;
}
// make options.debug
if (this.options.debug === true) {
this.options.debug = 'all';
} else if (Array.isArray(this.options.debug)) {
(function() {
var d = {};
$.each(self.options.debug, function() {
d[this] = true;
});
self.options.debug = d;
})();
} else {
this.options.debug = false;
}
/**
* Original functions evacuated by conflict check
*
* @type Object
*/
this.noConflicts = {};
/**
* Check and save conflicts with bootstrap etc
*
* @type Function
*/
this.noConflict = function() {
$.each(conflictChecks, function(i, p) {
if ($.fn[p] && typeof $.fn[p].noConflict === 'function') {
self.noConflicts[p] = $.fn[p].noConflict();
}
});
};
// do check conflict
this.noConflict();
/**
* Is elFinder over CORS
*
* @type Boolean
**/
this.isCORS = false;
// configure for CORS
(function(){
if (typeof self.options.cors !== 'undefined' && self.options.cors !== null) {
self.isCORS = self.options.cors? true : false;
} else {
var parseUrl = document.createElement('a'),
parseUploadUrl,
selfProtocol = window.location.protocol,
portReg = function(protocol) {
protocol = (!protocol || protocol === ':')? selfProtocol : protocol;
return protocol === 'https:'? /\:443$/ : /\:80$/;
},
selfHost = window.location.host.replace(portReg(selfProtocol), '');
parseUrl.href = opts.url;
if (opts.urlUpload && (opts.urlUpload !== opts.url)) {
parseUploadUrl = document.createElement('a');
parseUploadUrl.href = opts.urlUpload;
}
if (selfHost !== parseUrl.host.replace(portReg(parseUrl.protocol), '')
|| (parseUrl.protocol !== ':'&& parseUrl.protocol !== '' && (selfProtocol !== parseUrl.protocol))
|| (parseUploadUrl &&
(selfHost !== parseUploadUrl.host.replace(portReg(parseUploadUrl.protocol), '')
|| (parseUploadUrl.protocol !== ':' && parseUploadUrl.protocol !== '' && (selfProtocol !== parseUploadUrl.protocol))
)
)
) {
self.isCORS = true;
}
}
if (self.isCORS) {
if (!$.isPlainObject(self.options.customHeaders)) {
self.options.customHeaders = {};
}
if (!$.isPlainObject(self.options.xhrFields)) {
self.options.xhrFields = {};
}
self.options.requestType = 'post';
self.options.customHeaders['X-Requested-With'] = 'XMLHttpRequest';
self.options.xhrFields['withCredentials'] = true;
}
})();
/**
* Ajax request type
*
* @type String
* @default "get"
**/
this.requestType = /^(get|post)$/i.test(this.options.requestType) ? this.options.requestType.toLowerCase() : 'get';
// set `requestMaxConn` by option
requestMaxConn = Math.max(parseInt(this.options.requestMaxConn), 1);
/**
* Custom data that given as options
*
* @type Object
* @default {}
*/
this.optsCustomData = $.isPlainObject(this.options.customData) ? this.options.customData : {};
/**
* Any data to send across every ajax request
*
* @type Object
* @default {}
**/
this.customData = Object.assign({}, this.optsCustomData);
/**
* Previous custom data from connector
*
* @type Object|null
*/
this.prevCustomData = null;
/**
* Any custom headers to send across every ajax request
*
* @type Object
* @default {}
*/
this.customHeaders = $.isPlainObject(this.options.customHeaders) ? this.options.customHeaders : {};
/**
* Any custom xhrFields to send across every ajax request
*
* @type Object
* @default {}
*/
this.xhrFields = $.isPlainObject(this.options.xhrFields) ? this.options.xhrFields : {};
/**
* Replace XMLHttpRequest.prototype.send to extended function for 3rd party libs XHR request etc.
*
* @type Function
*/
this.replaceXhrSend = function() {
if (! savedXhrSend) {
savedXhrSend = XMLHttpRequest.prototype.send;
}
XMLHttpRequest.prototype.send = function() {
var xhr = this;
// set request headers
if (self.customHeaders) {
$.each(self.customHeaders, function(key) {
xhr.setRequestHeader(key, this);
});
}
// set xhrFields
if (self.xhrFields) {
$.each(self.xhrFields, function(key) {
if (key in xhr) {
xhr[key] = this;
}
});
}
return savedXhrSend.apply(this, arguments);
};
};
/**
* Restore saved original XMLHttpRequest.prototype.send
*
* @type Function
*/
this.restoreXhrSend = function() {
savedXhrSend && (XMLHttpRequest.prototype.send = savedXhrSend);
};
/**
* command names for into queue for only cwd requests
* these commands aborts before `open` request
*
* @type Array
* @default ['tmb', 'parents']
*/
this.abortCmdsOnOpen = this.options.abortCmdsOnOpen || ['tmb', 'parents'];
/**
* ui.nav id prefix
*
* @type String
*/
this.navPrefix = 'nav' + (elFinder.prototype.uniqueid? elFinder.prototype.uniqueid : '') + '-';
/**
* ui.cwd id prefix
*
* @type String
*/
this.cwdPrefix = elFinder.prototype.uniqueid? ('cwd' + elFinder.prototype.uniqueid + '-') : '';
// Increment elFinder.prototype.uniqueid
++elFinder.prototype.uniqueid;
/**
* URL to upload files
*
* @type String
**/
this.uploadURL = opts.urlUpload || opts.url;
/**
* Events namespace
*
* @type String
**/
this.namespace = namespace;
/**
* Today timestamp
*
* @type Number
**/
this.today = (new Date(date.getFullYear(), date.getMonth(), date.getDate())).getTime()/1000;
/**
* Yesterday timestamp
*
* @type Number
**/
this.yesterday = this.today - 86400;
utc = this.options.UTCDate ? 'UTC' : '';
this.getHours = 'get'+utc+'Hours';
this.getMinutes = 'get'+utc+'Minutes';
this.getSeconds = 'get'+utc+'Seconds';
this.getDate = 'get'+utc+'Date';
this.getDay = 'get'+utc+'Day';
this.getMonth = 'get'+utc+'Month';
this.getFullYear = 'get'+utc+'FullYear';
/**
* elFinder node z-index (auto detect on elFinder load)
*
* @type null | Number
**/
this.zIndex;
/**
* Current search status
*
* @type Object
*/
this.searchStatus = {
state : 0, // 0: search ended, 1: search started, 2: in search result
query : '',
target : '',
mime : '',
mixed : false, // in multi volumes search: false or Array that target volume ids
ininc : false // in incremental search
};
/**
* Interface language
*
* @type String
* @default "en"
**/
this.lang = this.storage('lang') || this.options.lang;
if (this.lang === 'jp') {
this.lang = this.options.lang = 'ja';
}
this.viewType = this.storage('view') || this.options.defaultView || 'icons';
this.sortType = this.storage('sortType') || this.options.sortType || 'name';
this.sortOrder = this.storage('sortOrder') || this.options.sortOrder || 'asc';
this.sortStickFolders = this.storage('sortStickFolders');
if (this.sortStickFolders === null) {
this.sortStickFolders = !!this.options.sortStickFolders;
} else {
this.sortStickFolders = !!this.sortStickFolders;
}
this.sortAlsoTreeview = this.storage('sortAlsoTreeview');
if (this.sortAlsoTreeview === null) {
this.sortAlsoTreeview = !!this.options.sortAlsoTreeview;
} else {
this.sortAlsoTreeview = !!this.sortAlsoTreeview;
}
this.sortRules = $.extend(true, {}, this._sortRules, this.options.sortRules);
$.each(this.sortRules, function(name, method) {
if (typeof method != 'function') {
delete self.sortRules[name];
}
});
this.compare = $.proxy(this.compare, this);
/**
* Delay in ms before open notification dialog
*
* @type Number
* @default 500
**/
this.notifyDelay = this.options.notifyDelay > 0 ? parseInt(this.options.notifyDelay) : 500;
/**
* Dragging UI Helper object
*
* @type jQuery | null
**/
this.draggingUiHelper = null;
/**
* Base droppable options
*
* @type Object
**/
this.droppable = {
greedy : true,
tolerance : 'pointer',
accept : '.elfinder-cwd-file-wrapper,.elfinder-navbar-dir,.elfinder-cwd-file,.elfinder-cwd-filename',
hoverClass : this.res('class', 'adroppable'),
classes : { // Deprecated hoverClass jQueryUI>=1.12.0
'ui-droppable-hover': this.res('class', 'adroppable')
},
autoDisable: true, // elFinder original, see jquery.elfinder.js
drop : function(e, ui) {
var dst = $(this),
targets = $.grep(ui.helper.data('files')||[], function(h) { return h? true : false; }),
result = [],
dups = [],
faults = [],
isCopy = ui.helper.hasClass('elfinder-drag-helper-plus'),
c = 'class',
cnt, hash, i, h;
if (typeof e.button === 'undefined' || ui.helper.data('namespace') !== namespace || ! self.insideWorkzone(e.pageX, e.pageY)) {
return false;
}
if (dst.hasClass(self.res(c, 'cwdfile'))) {
hash = self.cwdId2Hash(dst.attr('id'));
} else if (dst.hasClass(self.res(c, 'navdir'))) {
hash = self.navId2Hash(dst.attr('id'));
} else {
hash = cwd;
}
cnt = targets.length;
while (cnt--) {
h = targets[cnt];
// ignore drop into itself or in own location
if (h != hash && files[h].phash != hash) {
result.push(h);
} else {
((isCopy && h !== hash && files[hash].write)? dups : faults).push(h);
}
}
if (faults.length) {
return false;
}
ui.helper.data('droped', true);
if (dups.length) {
ui.helper.hide();
self.exec('duplicate', dups, {_userAction: true});
}
if (result.length) {
ui.helper.hide();
self.clipboard(result, !isCopy);
self.exec('paste', hash, {_userAction: true}, hash).always(function(){
self.clipboard([]);
self.trigger('unlockfiles', {files : targets});
});
self.trigger('drop', {files : targets});
}
}
};
/**
* Return true if filemanager is active
*
* @return Boolean
**/
this.enabled = function() {
return enabled && this.visible();
};
/**
* Return true if filemanager is visible
*
* @return Boolean
**/
this.visible = function() {
return node[0].elfinder && node.is(':visible');
};
/**
* Return file is root?
*
* @param Object target file object
* @return Boolean
*/
this.isRoot = function(file) {
return (file.isroot || ! file.phash)? true : false;
};
/**
* Return root dir hash for current working directory
*
* @param String target hash
* @param Boolean include fake parent (optional)
* @return String
*/
this.root = function(hash, fake) {
hash = hash || cwd;
var dir, i;
if (! fake) {
$.each(self.roots, function(id, rhash) {
if (hash.indexOf(id) === 0) {
dir = rhash;
return false;
}
});
if (dir) {
return dir;
}
}
dir = files[hash];
while (dir && dir.phash && (fake || ! dir.isroot)) {
dir = files[dir.phash];
}
if (dir) {
return dir.hash;
}
while (i in files && files.hasOwnProperty(i)) {
dir = files[i];
if (dir.mime === 'directory' && !dir.phash && dir.read) {
return dir.hash;
}
}
return '';
};
/**
* Return current working directory info
*
* @return Object
*/
this.cwd = function() {
return files[cwd] || {};
};
/**
* Return required cwd option
*
* @param String option name
* @param String target hash (optional)
* @return mixed
*/
this.option = function(name, target) {
var res, item;
target = target || cwd;
if (self.optionsByHashes[target] && typeof self.optionsByHashes[target][name] !== 'undefined') {
return self.optionsByHashes[target][name];
}
if (self.hasVolOptions && cwd !== target && (!(item = self.file(target)) || item.phash !== cwd)) {
res = '';
$.each(self.volOptions, function(id, opt) {
if (target.indexOf(id) === 0) {
res = opt[name] || '';
return false;
}
});
return res;
} else {
return cwdOptions[name] || '';
}
};
/**
* Return disabled commands by each folder
*
* @param Array target hashes
* @return Array
*/
this.getDisabledCmds = function(targets, flip) {
var disabled = {'hidden': true};
if (! Array.isArray(targets)) {
targets = [ targets ];
}
$.each(targets, function(i, h) {
var disCmds = self.option('disabledFlip', h);
if (disCmds) {
Object.assign(disabled, disCmds);
}
});
return flip? disabled : Object.keys(disabled);
};
/**
* Return file data from current dir or tree by it's hash
*
* @param String file hash
* @return Object
*/
this.file = function(hash, alsoHidden) {
return hash? (files[hash] || (alsoHidden? hiddenFiles[hash] : void(0))) : void(0);
};
/**
* Return all cached files
*
* @param String parent hash
* @return Object
*/
this.files = function(phash) {
var items = {};
if (phash) {
if (!ownFiles[phash]) {
return {};
}
$.each(ownFiles[phash], function(h) {
if (files[h]) {
items[h] = files[h];
} else {
delete ownFiles[phash][h];
}
});
return Object.assign({}, items);
}
return Object.assign({}, files);
};
/**
* Return list of file parents hashes include file hash
*
* @param String file hash
* @return Array
*/
this.parents = function(hash) {
var parents = [],
dir;
while (hash && (dir = this.file(hash))) {
parents.unshift(dir.hash);
hash = dir.phash;
}
return parents;
};
this.path2array = function(hash, i18) {
var file,
path = [];
while (hash) {
if ((file = files[hash]) && file.hash) {
path.unshift(i18 && file.i18 ? file.i18 : file.name);
hash = file.isroot? null : file.phash;
} else {
path = [];
break;
}
}
return path;
};
/**
* Return file path or Get path async with jQuery.Deferred
*
* @param Object file
* @param Boolean i18
* @param Object asyncOpt
* @return String|jQuery.Deferred
*/
this.path = function(hash, i18, asyncOpt) {
var path = files[hash] && files[hash].path
? files[hash].path
: this.path2array(hash, i18).join(cwdOptions.separator);
if (! asyncOpt || ! files[hash]) {
return path;
} else {
asyncOpt = Object.assign({notify: {type : 'parents', cnt : 1, hideCnt : true}}, asyncOpt);
var dfd = $.Deferred(),
notify = asyncOpt.notify,
noreq = false,
req = function() {
self.request({
data : {cmd : 'parents', target : files[hash].phash},
notify : notify,
preventFail : true
})
.done(done)
.fail(function() {
dfd.reject();
});
},
done = function() {
self.one('parentsdone', function() {
path = self.path(hash, i18);
if (path === '' && noreq) {
//retry with request
noreq = false;
req();
} else {
if (notify) {
clearTimeout(ntftm);
notify.cnt = -(parseInt(notify.cnt || 0));
self.notify(notify);
}
dfd.resolve(path);
}
});
},
ntftm;
if (path) {
return dfd.resolve(path);
} else {
if (self.ui['tree']) {
// try as no request
if (notify) {
ntftm = setTimeout(function() {
self.notify(notify);
}, self.notifyDelay);
}
noreq = true;
done(true);
} else {
req();
}
return dfd;
}
}
};
/**
* Return file url if set
*
* @param String file hash
* @param Object Options
* @return String
*/
this.url = function(hash, o) {
var file = files[hash],
opts = o || {},
async = opts.async || false,
temp = opts.temporary || false,
dfrd = async? $.Deferred() : null,
getUrl = function(url) {
if (url) {
return url;
}
if (file.url) {
return file.url;
}
if (typeof baseUrl === 'undefined') {
baseUrl = self.option('url', (!self.isRoot(file) && file.phash) || file.hash);
}
if (baseUrl) {
return baseUrl + $.map(self.path2array(hash), function(n) { return encodeURIComponent(n); }).slice(1).join('/');
}
var params = Object.assign({}, self.customData, {
cmd: 'file',
target: file.hash
});
if (self.oldAPI) {
params.cmd = 'open';
params.current = file.phash;
}
return self.options.url + (self.options.url.indexOf('?') === -1 ? '?' : '&') + $.param(params, true);
},
baseUrl, res;
if (!file || !file.read) {
return async? dfrd.resolve('') : '';
}
if (file.url == '1' || (temp && !file.url && !(baseUrl = self.option('url', (!self.isRoot(file) && file.phash) || file.hash)))) {
this.request({
data : { cmd : 'url', target : hash, options : { temporary: temp? 1 : 0 } },
preventDefault : true,
options: {async: async},
notify: async? {type : temp? 'file' : 'url', cnt : 1, hideCnt : true} : {}
})
.done(function(data) {
file.url = data.url || '';
})
.fail(function() {
file.url = '';
})
.always(function() {
var url;
if (file.url && temp) {
url = file.url;
file.url = '1'; // restore
}
if (async) {
dfrd.resolve(getUrl(url));
} else {
return getUrl(url);
}
});
} else {
if (async) {
dfrd.resolve(getUrl());
} else {
return getUrl();
}
}
if (async) {
return dfrd;
}
};
/**
* Return file url for open in elFinder
*
* @param String file hash
* @param Boolean for download link
* @return String
*/
this.openUrl = function(hash, download) {
var file = files[hash],
url = '';
if (!file || !file.read) {
return '';
}
if (!download) {
if (file.url) {
if (file.url != 1) {
url = file.url;
}
} else if (cwdOptions.url && file.hash.indexOf(self.cwd().volumeid) === 0) {
url = cwdOptions.url + $.map(this.path2array(hash), function(n) { return encodeURIComponent(n); }).slice(1).join('/');
}
if (url) {
url += (url.match(/\?/)? '&' : '?') + '_'.repeat((url.match(/[\?&](_+)t=/g) || ['&t=']).sort().shift().match(/[\?&](_*)t=/)[1].length + 1) + 't=' + (file.ts || parseInt(+new Date()/1000));
return url;
}
}
url = this.options.url;
url = url + (url.indexOf('?') === -1 ? '?' : '&')
+ (this.oldAPI ? 'cmd=open&current='+file.phash : 'cmd=file')
+ '&target=' + file.hash
+ '&_t=' + (file.ts || parseInt(+new Date()/1000));
if (download) {
url += '&download=1';
}
$.each(this.customData, function(key, val) {
url += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(val);
});
return url;
};
/**
* Return thumbnail url
*
* @param Object file object
* @return String
*/
this.tmb = function(file) {
var tmbUrl, tmbCrop,
cls = 'elfinder-cwd-bgurl',
url = '';
if ($.isPlainObject(file)) {
if (self.searchStatus.state && file.hash.indexOf(self.cwd().volumeid) !== 0) {
tmbUrl = self.option('tmbUrl', file.hash);
tmbCrop = self.option('tmbCrop', file.hash);
} else {
tmbUrl = cwdOptions['tmbUrl'];
tmbCrop = cwdOptions['tmbCrop'];
}
if (tmbCrop) {
cls += ' elfinder-cwd-bgurl-crop';
}
if (tmbUrl === 'self' && file.mime.indexOf('image/') === 0) {
url = self.openUrl(file.hash);
cls += ' elfinder-cwd-bgself';
} else if ((self.oldAPI || tmbUrl) && file && file.tmb && file.tmb != 1) {
url = tmbUrl + file.tmb;
} else if (self.newAPI && file && file.tmb && file.tmb != 1) {
url = file.tmb;
}
if (url) {
if (file.ts && tmbUrl !== 'self') {
url += (url.match(/\?/)? '&' : '?') + '_t=' + file.ts;
}
return { url: url, className: cls };
}
}
return false;
};
/**
* Return selected files hashes
*
* @return Array
**/
this.selected = function() {
return selected.slice(0);
};
/**
* Return selected files info
*
* @return Array
*/
this.selectedFiles = function() {
return $.map(selected, function(hash) { return files[hash] ? Object.assign({}, files[hash]) : null; });
};
/**
* Return true if file with required name existsin required folder
*
* @param String file name
* @param String parent folder hash
* @return Boolean
*/
this.fileByName = function(name, phash) {
var hash;
for (hash in files) {
if (files.hasOwnProperty(hash) && files[hash].phash == phash && files[hash].name == name) {
return files[hash];
}
}
};
/**
* Valid data for required command based on rules
*
* @param String command name
* @param Object cammand's data
* @return Boolean
*/
this.validResponse = function(cmd, data) {
return data.error || this.rules[this.rules[cmd] ? cmd : 'defaults'](data);
};
/**
* Return bytes from ini formated size
*
* @param String ini formated size
* @return Integer
*/
this.returnBytes = function(val) {
var last;
if (isNaN(val)) {
if (! val) {
val = '';
}
// for ex. 1mb, 1KB
val = val.replace(/b$/i, '');
last = val.charAt(val.length - 1).toLowerCase();
val = val.replace(/[tgmk]$/i, '');
if (last == 't') {
val = val * 1024 * 1024 * 1024 * 1024;
} else if (last == 'g') {
val = val * 1024 * 1024 * 1024;
} else if (last == 'm') {
val = val * 1024 * 1024;
} else if (last == 'k') {
val = val * 1024;
}
val = isNaN(val)? 0 : parseInt(val);
} else {
val = parseInt(val);
if (val < 1) val = 0;
}
return val;
};
/**
* Process ajax request.
* Fired events :
* @todo
* @example
* @todo
* @return $.Deferred
*/
this.request = function(opts) {
var self = this,
o = this.options,
dfrd = $.Deferred(),
// request ID
reqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16),
// request data
data = Object.assign({}, self.customData, {mimes : o.onlyMimes}, opts.data || opts),
// command name
cmd = data.cmd,
// request type is binary
isBinary = (opts.options || {}).dataType === 'binary',
// current cmd is "open"
isOpen = (!opts.asNotOpen && cmd === 'open'),
// call default fail callback (display error dialog) ?
deffail = !(isBinary || opts.preventDefault || opts.preventFail),
// call default success callback ?
defdone = !(isBinary || opts.preventDefault || opts.preventDone),
// options for notify dialog
notify = Object.assign({}, opts.notify),
// make cancel button
cancel = !!opts.cancel,
// do not normalize data - return as is
raw = isBinary || !!opts.raw,
// sync files on request fail
syncOnFail = opts.syncOnFail,
// use lazy()
lazy = !!opts.lazy,
// prepare function before done()
prepare = opts.prepare,
// navigate option object when cmd done
navigate = opts.navigate,
// open notify dialog timeout
timeout,
// use browser cache
useCache = (opts.options || {}).cache,
// request options
options = Object.assign({
url : o.url,
async : true,
type : this.requestType,
dataType : 'json',
cache : (self.api >= 2.1029), // api >= 2.1029 has unique request ID
data : data,
headers : this.customHeaders,
xhrFields: this.xhrFields
}, opts.options || {}),
/**
* Default success handler.
* Call default data handlers and fire event with command name.
*
* @param Object normalized response data
* @return void
**/
done = function(data) {
data.warning && self.error(data.warning);
if (isOpen) {
open(data);
} else {
self.updateCache(data);
}
data.changed && data.changed.length && change(data.changed);
self.lazy(function() {
// fire some event to update cache/ui
data.removed && data.removed.length && self.remove(data);
data.added && data.added.length && self.add(data);
data.changed && data.changed.length && self.change(data);
}).then(function() {
// fire event with command name
return self.lazy(function() {
self.trigger(cmd, data, false);
});
}).then(function() {
// fire event with command name + 'done'
return self.lazy(function() {
self.trigger(cmd + 'done');
});
}).then(function() {
// make toast message
if (data.toasts && Array.isArray(data.toasts)) {
$.each(data.toasts, function() {
this.msg && self.toast(this);
});
}
// force update content
data.sync && self.sync();
});
},
/**
* Request error handler. Reject dfrd with correct error message.
*
* @param jqxhr request object
* @param String request status
* @return void
**/
error = function(xhr, status) {
var error, data,
d = self.options.debug;
switch (status) {
case 'abort':
error = xhr.quiet ? '' : ['errConnect', 'errAbort'];
break;
case 'timeout':
error = ['errConnect', 'errTimeout'];
break;
case 'parsererror':
error = ['errResponse', 'errDataNotJSON'];
if (xhr.responseText) {
if (! cwd || (d && (d === 'all' || d['backend-error']))) {
error.push(xhr.responseText);
}
}
break;
default:
if (xhr.responseText) {
// check responseText, Is that JSON?
try {
data = JSON.parse(xhr.responseText);
if (data && data.error) {
error = data.error;
}
} catch(e) {}
}
if (! error) {
if (xhr.status == 403) {
error = ['errConnect', 'errAccess', 'HTTP error ' + xhr.status];
} else if (xhr.status == 404) {
error = ['errConnect', 'errNotFound', 'HTTP error ' + xhr.status];
} else if (xhr.status >= 500) {
error = ['errResponse', 'errServerError', 'HTTP error ' + xhr.status];
} else {
if (xhr.status == 414 && options.type === 'get') {
// retry by POST method
options.type = 'post';
self.abortXHR(xhr);
dfrd.xhr = xhr = self.transport.send(options).fail(error).done(success);
return;
}
error = xhr.quiet ? '' : ['errConnect', 'HTTP error ' + xhr.status];
}
}
}
self.trigger(cmd + 'done');
dfrd.reject({error: error}, xhr, status);
},
/**
* Request success handler. Valid response data and reject/resolve dfrd.
*
* @param Object response data
* @param String request status
* @return void
**/
success = function(response) {
var d = self.options.debug;
// Set currrent request command name
self.currentReqCmd = cmd;
if (response.debug && (!d || d !== 'all')) {
if (!d) {
d = self.options.debug = {};
}
d['backend-error'] = true;
d['warning'] = true;
}
if (raw) {
self.abortXHR(xhr);
response && response.debug && self.debug('backend-debug', response);
return dfrd.resolve(response);
}
if (!response) {
return dfrd.reject({error :['errResponse', 'errDataEmpty']}, xhr, response);
} else if (!$.isPlainObject(response)) {
return dfrd.reject({error :['errResponse', 'errDataNotJSON']}, xhr, response);
} else if (response.error) {
if (isOpen) {
// check leafRoots
$.each(self.leafRoots, function(phash, roots) {
self.leafRoots[phash] = $.grep(roots, function(h) { return h !== data.target; });
});
}
return dfrd.reject({error :response.error}, xhr, response);
}
var resolve = function() {
var pushLeafRoots = function(name) {
if (self.leafRoots[data.target] && response[name]) {
$.each(self.leafRoots[data.target], function(i, h) {
var root;
if (root = self.file(h)) {
response[name].push(root);
}
});
}
},
setTextMimes = function() {
self.textMimes = {};
$.each(self.res('mimes', 'text'), function() {
self.textMimes[this.toLowerCase()] = true;
});
},
actionTarget;
if (isOpen) {
pushLeafRoots('files');
} else if (cmd === 'tree') {
pushLeafRoots('tree');
}
response = self.normalize(response);
if (!self.validResponse(cmd, response)) {
return dfrd.reject({error :(response.norError || 'errResponse')}, xhr, response);
}
if (isOpen) {
if (!self.api) {
self.api = response.api || 1;
if (self.api == '2.0' && typeof response.options.uploadMaxSize !== 'undefined') {
self.api = '2.1';
}
self.newAPI = self.api >= 2;
self.oldAPI = !self.newAPI;
}
if (response.textMimes && Array.isArray(response.textMimes)) {
self.resources.mimes.text = response.textMimes;
setTextMimes();
}
!self.textMimes && setTextMimes();
if (response.options) {
cwdOptions = Object.assign({}, cwdOptionsDefault, response.options);
}
if (response.netDrivers) {
self.netDrivers = response.netDrivers;
}
if (response.maxTargets) {
self.maxTargets = response.maxTargets;
}
if (!!data.init) {
self.uplMaxSize = self.returnBytes(response.uplMaxSize);
self.uplMaxFile = !!response.uplMaxFile? Math.max(parseInt(response.uplMaxFile), 50) : 20;
}
}
if (typeof prepare === 'function') {
prepare(response);
}
if (navigate) {
actionTarget = navigate.target || 'added';
if (response[actionTarget] && response[actionTarget].length) {
self.one(cmd + 'done', function() {
var targets = response[actionTarget],
newItems = self.findCwdNodes(targets),
inCwdHashes = function() {
var cwdHash = self.cwd().hash;
return $.map(targets, function(f) { return (f.phash && cwdHash === f.phash)? f.hash : null; });
},
hashes = inCwdHashes(),
makeToast = function(t) {
var node = void(0),
data = t.action? t.action.data : void(0),
cmd, msg, done;
if ((data || hashes.length) && t.action && (msg = t.action.msg) && (cmd = t.action.cmd) && (!t.action.cwdNot || t.action.cwdNot !== self.cwd().hash)) {
done = t.action.done;
data = t.action.data;
node = $('<div/>')
.append(
$('<button type="button" class="ui-button ui-widget ui-state-default ui-corner-all elfinder-tabstop"><span class="ui-button-text">'
+self.i18n(msg)
+'</span></button>')
.on('mouseenter mouseleave', function(e) {
$(this).toggleClass('ui-state-hover', e.type == 'mouseenter');
})
.on('click', function() {
self.exec(cmd, data || hashes, {_userAction: true, _currentType: 'toast', _currentNode: $(this) });
if (done) {
self.one(cmd+'done', function() {
if (typeof done === 'function') {
done();
} else if (done === 'select') {
self.trigger('selectfiles', {files : inCwdHashes()});
}
});
}
})
);
}
delete t.action;
t.extNode = node;
return t;
};
if (! navigate.toast) {
navigate.toast = {};
}
!navigate.noselect && self.trigger('selectfiles', {files : self.searchStatus.state > 1 ? $.map(targets, function(f) { return f.hash; }) : hashes});
if (newItems.length) {
if (!navigate.noscroll) {
newItems.first().trigger('scrolltoview', {blink : false});
self.resources.blink(newItems, 'lookme');
}
if ($.isPlainObject(navigate.toast.incwd)) {
self.toast(makeToast(navigate.toast.incwd));
}
} else {
if ($.isPlainObject(navigate.toast.inbuffer)) {
self.toast(makeToast(navigate.toast.inbuffer));
}
}
});
}
}
dfrd.resolve(response);
response.debug && self.debug('backend-debug', response);
};
self.abortXHR(xhr);
lazy? self.lazy(resolve) : resolve();
},
xhr, _xhr,
xhrAbort = function(e) {
if (xhr && xhr.state() === 'pending') {
self.abortXHR(xhr, { quiet: true , abort: true });
if (!e || (e.type !== 'unload' && e.type !== 'destroy')) {
self.autoSync();
}
}
},
abort = function(e){
self.trigger(cmd + 'done');
if (e.type == 'autosync') {
if (e.data.action != 'stop') return;
} else if (e.type != 'unload' && e.type != 'destroy' && e.type != 'openxhrabort') {
if (!e.data.added || !e.data.added.length) {
return;
}
}
xhrAbort(e);
},
request = function(mode) {
var queueAbort = function() {
syncOnFail = false;
dfrd.reject();
};
if (mode) {
if (mode === 'cmd') {
return cmd;
}
}
if (isOpen) {
if (requestQueueSkipOpen) {
return dfrd.reject();
}
requestQueueSkipOpen = true;
}
dfrd.always(function() {
delete options.headers['X-elFinderReqid'];
}).fail(function(error, xhr, response) {
var errData = {
cmd: cmd,
err: error,
xhr: xhr,
rc: response
};
// unset this cmd queue when user canceling
// see notify : function - `cancel.reject(0);`
if (error === 0) {
if (requestQueue.length) {
requestQueue = $.grep(requestQueue, function(req) {
return (req('cmd') === cmd) ? false : true;
});
}
}
// trigger "requestError" event
self.trigger('requestError', errData);
if (errData._event && errData._event.isDefaultPrevented()) {
deffail = false;
syncOnFail = false;
if (error) {
error.error = '';
}
}
// abort xhr
xhrAbort();
if (isOpen) {
openDir = self.file(data.target);
openDir && openDir.volumeid && self.isRoot(openDir) && delete self.volumeExpires[openDir.volumeid];
}
self.trigger(cmd + 'fail', response);
if (error) {
deffail ? self.error(error) : self.debug('error', self.i18n(error));
}
syncOnFail && self.sync();
});
if (!cmd) {
syncOnFail = false;
return dfrd.reject({error :'errCmdReq'});
}
if (self.maxTargets && data.targets && data.targets.length > self.maxTargets) {
syncOnFail = false;
return dfrd.reject({error :['errMaxTargets', self.maxTargets]});
}
defdone && dfrd.done(done);
// quiet abort not completed "open" requests
if (isOpen) {
while ((_xhr = queue.pop())) {
_xhr.queueAbort();
}
if (cwd !== data.target) {
while ((_xhr = cwdQueue.pop())) {
_xhr.queueAbort();
}
}
}
// trigger abort autoSync for commands to add the item
if ($.inArray(cmd, (self.cmdsToAdd + ' autosync').split(' ')) !== -1) {
if (cmd !== 'autosync') {
self.autoSync('stop');
dfrd.always(function() {
self.autoSync();
});
}
self.trigger('openxhrabort');
}
delete options.preventFail;
if (self.api >= 2.1029) {
if (useCache) {
options.headers['X-elFinderReqid'] = reqId;
} else {
Object.assign(options.data, { reqid : reqId });
}
}
// function for set value of this syncOnFail
dfrd.syncOnFail = function(state) {
syncOnFail = !!state;
};
requestCnt++;
dfrd.xhr = xhr = self.transport.send(options).always(function() {
// set responseURL from native xhr object
if (options._xhr && typeof options._xhr.responseURL !== 'undefined') {
xhr.responseURL = options._xhr.responseURL || '';
}
--requestCnt;
if (requestQueue.length) {
requestQueue.shift()();
} else {
requestQueueSkipOpen = false;
}
}).fail(error).done(success);
if (self.api >= 2.1029) {
xhr._requestId = reqId;
}
if (isOpen || (data.compare && cmd === 'info')) {
// regist function queueAbort
xhr.queueAbort = queueAbort;
// add autoSync xhr into queue
queue.unshift(xhr);
// bind abort()
data.compare && self.bind(self.cmdsToAdd + ' autosync openxhrabort', abort);
dfrd.always(function() {
var ndx = $.inArray(xhr, queue);
data.compare && self.unbind(self.cmdsToAdd + ' autosync openxhrabort', abort);
ndx !== -1 && queue.splice(ndx, 1);
});
} else if ($.inArray(cmd, self.abortCmdsOnOpen) !== -1) {
// regist function queueAbort
xhr.queueAbort = queueAbort;
// add "open" xhr, only cwd xhr into queue
cwdQueue.unshift(xhr);
dfrd.always(function() {
var ndx = $.inArray(xhr, cwdQueue);
ndx !== -1 && cwdQueue.splice(ndx, 1);
});
}
// abort pending xhr on window unload or elFinder destroy
self.bind('unload destroy', abort);
dfrd.always(function() {
self.unbind('unload destroy', abort);
});
return dfrd;
},
queueingRequest = function() {
// show notify
if (notify.type && notify.cnt) {
if (cancel) {
notify.cancel = dfrd;
opts.eachCancel && (notify.id = +new Date());
}
timeout = setTimeout(function() {
self.notify(notify);
dfrd.always(function() {
notify.cnt = -(parseInt(notify.cnt)||0);
self.notify(notify);
});
}, self.notifyDelay);
dfrd.always(function() {
clearTimeout(timeout);
});
}
// queueing
if (isOpen) {
requestQueueSkipOpen = false;
}
if (requestCnt < requestMaxConn) {
// do request
return request();
} else {
if (isOpen) {
requestQueue.unshift(request);
} else {
requestQueue.push(request);
}
return dfrd;
}
},
bindData = {opts: opts, result: true},
openDir;
// prevent request initial request is completed
if (!self.api && !data.init) {
syncOnFail = false;
return dfrd.reject();
}
// trigger "request.cmd" that callback be able to cancel request by substituting "false" for "event.data.result"
self.trigger('request.' + cmd, bindData, true);
if (! bindData.result) {
self.trigger(cmd + 'done');
return dfrd.reject();
} else if (typeof bindData.result === 'object' && bindData.result.promise) {
bindData.result
.done(queueingRequest)
.fail(function() {
self.trigger(cmd + 'done');
dfrd.reject();
});
return dfrd;
}
return queueingRequest();
};
/**
* Call cache()
* Store info about files/dirs in "files" object.
*
* @param Array files
* @return void
*/
this.cache = function(dataArray) {
if (! Array.isArray(dataArray)) {
dataArray = [ dataArray ];
}
cache(dataArray);
};
/**
* Update file object caches by respose data object
*
* @param Object respose data object
* @return void
*/
this.updateCache = function(data) {
if ($.isPlainObject(data)) {
data.files && data.files.length && cache(data.files, 'files');
data.tree && data.tree.length && cache(data.tree, 'tree');
data.removed && data.removed.length && remove(data.removed);
data.added && data.added.length && cache(data.added, 'add');
data.changed && data.changed.length && change(data.changed, 'change');
}
};
/**
* Compare current files cache with new files and return diff
*
* @param Array new files
* @param String target folder hash
* @param Array exclude properties to compare
* @return Object
*/
this.diff = function(incoming, onlydir, excludeProps) {
var raw = {},
added = [],
removed = [],
changed = [],
excludes = null,
isChanged = function(hash) {
var l = changed.length;
while (l--) {
if (changed[l].hash == hash) {
return true;
}
}
};
$.each(incoming, function(i, f) {
raw[f.hash] = f;
});
// make excludes object
if (excludeProps && excludeProps.length) {
excludes = {};
$.each(excludeProps, function() {
excludes[this] = true;
});
}
// find removed
$.each(files, function(hash, f) {
if (! raw[hash] && (! onlydir || f.phash === onlydir)) {
removed.push(hash);
}
});
// compare files
$.each(raw, function(hash, file) {
var origin = files[hash],
orgKeys = {},
chkKeyLen;
if (!origin) {
added.push(file);
} else {
// make orgKeys object
$.each(Object.keys(origin), function() {
orgKeys[this] = true;
});
$.each(file, function(prop) {
delete orgKeys[prop];
if (! excludes || ! excludes[prop]) {
if (file[prop] !== origin[prop]) {
changed.push(file);
orgKeys = {};
return false;
}
}
});
chkKeyLen = Object.keys(orgKeys).length;
if (chkKeyLen !== 0) {
if (excludes) {
$.each(orgKeys, function(prop) {
if (excludes[prop]) {
--chkKeyLen;
}
});
}
(chkKeyLen !== 0) && changed.push(file);
}
}
});
// parents of removed dirs mark as changed (required for tree correct work)
$.each(removed, function(i, hash) {
var file = files[hash],
phash = file.phash;
if (phash
&& file.mime == 'directory'
&& $.inArray(phash, removed) === -1
&& raw[phash]
&& !isChanged(phash)) {
changed.push(raw[phash]);
}
});
return {
added : added,
removed : removed,
changed : changed
};
};
/**
* Sync content
*
* @return jQuery.Deferred
*/
this.sync = function(onlydir, polling) {
this.autoSync('stop');
var self = this,
compare = function(){
var c = '', cnt = 0, mtime = 0;
if (onlydir && polling) {
$.each(files, function(h, f) {
if (f.phash && f.phash === onlydir) {
++cnt;
mtime = Math.max(mtime, f.ts);
}
c = cnt+':'+mtime;
});
}
return c;
},
comp = compare(),
dfrd = $.Deferred().done(function() { self.trigger('sync'); }),
opts = [this.request({
data : {cmd : 'open', reload : 1, target : cwd, tree : (! onlydir && this.ui.tree) ? 1 : 0, compare : comp},
preventDefault : true
})],
exParents = function() {
var parents = [],
curRoot = self.file(self.root(cwd)),
curId = curRoot? curRoot.volumeid : null,
phash = self.cwd().phash,
isroot,pdir;
while(phash) {
if (pdir = self.file(phash)) {
if (phash.indexOf(curId) !== 0) {
parents.push( {target: phash, cmd: 'tree'} );
if (! self.isRoot(pdir)) {
parents.push( {target: phash, cmd: 'parents'} );
}
curRoot = self.file(self.root(phash));
curId = curRoot? curRoot.volumeid : null;
}
phash = pdir.phash;
} else {
phash = null;
}
}
return parents;
};
if (! onlydir && self.api >= 2) {
(cwd !== this.root()) && opts.push(this.request({
data : {cmd : 'parents', target : cwd},
preventDefault : true
}));
$.each(exParents(), function(i, data) {
opts.push(self.request({
data : {cmd : data.cmd, target : data.target},
preventDefault : true
}));
});
}
$.when.apply($, opts)
.fail(function(error, xhr) {
if (! polling || $.inArray('errOpen', error) !== -1) {
dfrd.reject(error);
self.parseError(error) && self.request({
data : {cmd : 'open', target : (self.lastDir('') || self.root()), tree : 1, init : 1},
notify : {type : 'open', cnt : 1, hideCnt : true}
});
} else {
dfrd.reject((error && xhr.status != 0)? error : void 0);
}
})
.done(function(odata) {
var pdata, argLen, i;
if (odata.cwd.compare) {
if (comp === odata.cwd.compare) {
return dfrd.reject();
}
}
// for 2nd and more requests
pdata = {tree : []};
// results marge of 2nd and more requests
argLen = arguments.length;
if (argLen > 1) {
for(i = 1; i < argLen; i++) {
if (arguments[i].tree && arguments[i].tree.length) {
pdata.tree.push.apply(pdata.tree, arguments[i].tree);
}
}
}
if (self.api < 2.1) {
if (! pdata.tree) {
pdata.tree = [];
}
pdata.tree.push(odata.cwd);
}
// data normalize
odata = self.normalize(odata);
if (!self.validResponse('open', odata)) {
return dfrd.reject((odata.norError || 'errResponse'));
}
pdata = self.normalize(pdata);
if (!self.validResponse('tree', pdata)) {
return dfrd.reject((pdata.norError || 'errResponse'));
}
var diff = self.diff(odata.files.concat(pdata && pdata.tree ? pdata.tree : []), onlydir);
diff.added.push(odata.cwd);
self.updateCache(diff);
// trigger events
diff.removed.length && self.remove(diff);
diff.added.length && self.add(diff);
diff.changed.length && self.change(diff);
return dfrd.resolve(diff);
})
.always(function() {
self.autoSync();
});
return dfrd;
};
this.upload = function(files) {
return this.transport.upload(files, this);
};
/**
* Arrays that has to unbind events
*
* @type Object
*/
this.toUnbindEvents = {};
/**
* Attach listener to events
* To bind to multiply events at once, separate events names by space
*
* @param String event(s) name(s)
* @param Object event handler or {done: handler}
* @param Boolean priority first
* @return elFinder
*/
this.bind = function(event, callback, priorityFirst) {
var i, len;
if (callback && (typeof callback === 'function' || typeof callback.done === 'function')) {
event = ('' + event).toLowerCase().replace(/^\s+|\s+$/g, '').split(/\s+/);
len = event.length;
for (i = 0; i < len; i++) {
if (listeners[event[i]] === void(0)) {
listeners[event[i]] = [];
}
listeners[event[i]][priorityFirst? 'unshift' : 'push'](callback);
}
}
return this;
};
/**
* Remove event listener if exists
* To un-bind to multiply events at once, separate events names by space
*
* @param String event(s) name(s)
* @param Function callback
* @return elFinder
*/
this.unbind = function(event, callback) {
var i, len, l, ci;
event = ('' + event).toLowerCase().split(/\s+/);
len = event.length;
for (i = 0; i < len; i++) {
if (l = listeners[event[i]]) {
ci = $.inArray(callback, l);
ci > -1 && l.splice(ci, 1);
}
}
callback = null;
return this;
};
/**
* Fire event - send notification to all event listeners
* In the callback `this` becames an event object
*
* @param String event type
* @param Object data to send across event
* @param Boolean allow modify data (call by reference of data) default: true
* @return elFinder
*/
this.trigger = function(evType, data, allowModify) {
var type = evType.toLowerCase(),
isopen = (type === 'open'),
dataIsObj = (typeof data === 'object'),
handlers = listeners[type] || [],
dones = [],
i, l, jst, event;
this.debug('event-'+type, data);
if (! dataIsObj || typeof allowModify === 'undefined') {
allowModify = true;
}
if (l = handlers.length) {
event = $.Event(type);
if (data) {
data._event = event;
}
if (allowModify) {
event.data = data;
}
for (i = 0; i < l; i++) {
if (! handlers[i]) {
// probably un-binded this handler
continue;
}
// handler is $.Deferred(), call all functions upon completion
if (handlers[i].done) {
dones.push(handlers[i].done);
continue;
}
// set `event.data` only callback has argument
if (handlers[i].length) {
if (!allowModify) {
// to avoid data modifications. remember about "sharing" passing arguments in js :)
if (typeof jst === 'undefined') {
try {
jst = JSON.stringify(data);
} catch(e) {
jst = false;
}
}
event.data = jst? JSON.parse(jst) : data;
}
}
try {
if (handlers[i].call(event, event, this) === false || event.isDefaultPrevented()) {
this.debug('event-stoped', event.type);
break;
}
} catch (ex) {
window.console && window.console.log && window.console.log(ex);
}
}
// call done functions
if (l = dones.length) {
for (i = 0; i < l; i++) {
try {
if (dones[i].call(event, event, this) === false || event.isDefaultPrevented()) {
this.debug('event-stoped', event.type + '(done)');
break;
}
} catch (ex) {
window.console && window.console.log && window.console.log(ex);
}
}
}
if (this.toUnbindEvents[type] && this.toUnbindEvents[type].length) {
$.each(this.toUnbindEvents[type], function(i, v) {
self.unbind(v.type, v.callback);
});
delete this.toUnbindEvents[type];
}
}
return this;
};
/**
* Get event listeners
*
* @param String event type
* @return Array listed event functions
*/
this.getListeners = function(event) {
return event? listeners[event.toLowerCase()] : listeners;
};
/**
* Bind keybord shortcut to keydown event
*
* @example
* elfinder.shortcut({
* pattern : 'ctrl+a',
* description : 'Select all files',
* callback : function(e) { ... },
* keypress : true|false (bind to keypress instead of keydown)
* })
*
* @param Object shortcut config
* @return elFinder
*/
this.shortcut = function(s) {
var patterns, pattern, code, i, parts;
if (this.options.allowShortcuts && s.pattern && $.isFunction(s.callback)) {
patterns = s.pattern.toUpperCase().split(/\s+/);
for (i= 0; i < patterns.length; i++) {
pattern = patterns[i];
parts = pattern.split('+');
code = (code = parts.pop()).length == 1
? (code > 0 ? code : code.charCodeAt(0))
: (code > 0 ? code : $.ui.keyCode[code]);
if (code && !shortcuts[pattern]) {
shortcuts[pattern] = {
keyCode : code,
altKey : $.inArray('ALT', parts) != -1,
ctrlKey : $.inArray('CTRL', parts) != -1,
shiftKey : $.inArray('SHIFT', parts) != -1,
type : s.type || 'keydown',
callback : s.callback,
description : s.description,
pattern : pattern
};
}
}
}
return this;
};
/**
* Registered shortcuts
*
* @type Object
**/
this.shortcuts = function() {
var ret = [];
$.each(shortcuts, function(i, s) {
ret.push([s.pattern, self.i18n(s.description)]);
});
return ret;
};
/**
* Get/set clipboard content.
* Return new clipboard content.
*
* @example
* this.clipboard([]) - clean clipboard
* this.clipboard([{...}, {...}], true) - put 2 files in clipboard and mark it as cutted
*
* @param Array new files hashes
* @param Boolean cut files?
* @return Array
*/
this.clipboard = function(hashes, cut) {
var map = function() { return $.map(clipboard, function(f) { return f.hash; }); };
if (hashes !== void(0)) {
clipboard.length && this.trigger('unlockfiles', {files : map()});
remember = {};
clipboard = $.map(hashes||[], function(hash) {
var file = files[hash];
if (file) {
remember[hash] = true;
return {
hash : hash,
phash : file.phash,
name : file.name,
mime : file.mime,
read : file.read,
locked : file.locked,
cut : !!cut
};
}
return null;
});
this.trigger('changeclipboard', {clipboard : clipboard.slice(0, clipboard.length)});
cut && this.trigger('lockfiles', {files : map()});
}
// return copy of clipboard instead of refrence
return clipboard.slice(0, clipboard.length);
};
/**
* Return true if command enabled
*
* @param String command name
* @param String|void hash for check of own volume's disabled cmds
* @return Boolean
*/
this.isCommandEnabled = function(name, dstHash) {
var disabled, cmd,
cvid = self.cwd().volumeid || '';
// In serach results use selected item hash to check
if (!dstHash && self.searchStatus.state > 1 && self.selected().length) {
dstHash = self.selected()[0];
}
if (dstHash && (! cvid || dstHash.indexOf(cvid) !== 0)) {
disabled = self.option('disabledFlip', dstHash);
//if (! disabled) {
// disabled = {};
//}
} else {
disabled = cwdOptions.disabledFlip/* || {}*/;
}
cmd = this._commands[name];
return cmd ? (cmd.alwaysEnabled || !disabled[name]) : false;
};
/**
* Exec command and return result;
*
* @param String command name
* @param String|Array usualy files hashes
* @param String|Array command options
* @param String|void hash for enabled check of own volume's disabled cmds
* @return $.Deferred
*/
this.exec = function(cmd, files, opts, dstHash) {
var dfrd, resType;
// apply commandMap for keyboard shortcut
if (!dstHash && this.commandMap[cmd] && this.commandMap[cmd] !== 'hidden') {
cmd = this.commandMap[cmd];
}
if (cmd === 'open') {
if (this.searchStatus.state || this.searchStatus.ininc) {
this.trigger('searchend', { noupdate: true });
}
this.autoSync('stop');
}
if (!dstHash && files) {
if ($.isArray(files)) {
if (files.length) {
dstHash = files[0];
}
} else {
dstHash = files;
}
}
dfrd = this._commands[cmd] && this.isCommandEnabled(cmd, dstHash)
? this._commands[cmd].exec(files, opts)
: $.Deferred().reject('No such command');
resType = typeof dfrd;
if (!(resType === 'object' && dfrd.promise)) {
self.debug('warning', '"cmd.exec()" should be returned "$.Deferred" but cmd "' + cmd + '" returned "' + resType + '"');
dfrd = $.Deferred().resolve();
}
this.trigger('exec', { dfrd : dfrd, cmd : cmd, files : files, opts : opts, dstHash : dstHash });
return dfrd;
};
/**
* Create and return dialog.
*
* @param String|DOMElement dialog content
* @param Object dialog options
* @return jQuery
*/
this.dialog = function(content, options) {
var dialog = $('<div/>').append(content).appendTo(node).elfinderdialog(options, self),
dnode = dialog.closest('.ui-dialog'),
resize = function(){
! dialog.data('draged') && dialog.is(':visible') && dialog.elfinderdialog('posInit');
};
if (dnode.length) {
self.bind('resize', resize);
dnode.on('remove', function() {
self.unbind('resize', resize);
});
}
return dialog;
};
/**
* Create and return toast.
*
* @param Object toast options - see ui/toast.js
* @return jQuery
*/
this.toast = function(options) {
return $('<div class="ui-front"/>').appendTo(this.ui.toast).elfindertoast(options || {}, this);
};
/**
* Return UI widget or node
*
* @param String ui name
* @return jQuery
*/
this.getUI = function(ui) {
return this.ui[ui] || (ui? $() : node);
};
/**
* Return elFinder.command instance or instances array
*
* @param String command name
* @return Object | Array
*/
this.getCommand = function(name) {
return name === void(0) ? this._commands : this._commands[name];
};
/**
* Resize elfinder node
*
* @param String|Number width
* @param String|Number height
* @return void
*/
this.resize = function(w, h) {
var getMargin = function() {
var m = node.outerHeight(true) - node.innerHeight(),
p = node;
while(p.get(0) !== heightBase.get(0)) {
p = p.parent();
m += p.outerHeight(true) - p.innerHeight();
if (! p.parent().length) {
// reached the document
break;
}
}
return m;
},
fit = ! node.hasClass('ui-resizable'),
prv = node.data('resizeSize') || {w: 0, h: 0},
mt, size = {};
if (heightBase && heightBase.data('resizeTm')) {
clearTimeout(heightBase.data('resizeTm'));
}
if (typeof h === 'string') {
if (mt = h.match(/^([0-9.]+)%$/)) {
// setup heightBase
if (! heightBase || ! heightBase.length) {
heightBase = $(window);
}
if (! heightBase.data('marginToMyNode')) {
heightBase.data('marginToMyNode', getMargin());
}
if (! heightBase.data('fitToBaseFunc')) {
heightBase.data('fitToBaseFunc', function(e) {
var tm = heightBase.data('resizeTm');
e.preventDefault();
e.stopPropagation();
tm && cancelAnimationFrame(tm);
if (! node.hasClass('elfinder-fullscreen') && (!self.UA.Mobile || heightBase.data('rotated') !== self.UA.Rotated)) {
heightBase.data('rotated', self.UA.Rotated);
heightBase.data('resizeTm', requestAnimationFrame(function() {
self.restoreSize();
}));
}
});
}
if (typeof heightBase.data('rotated') === 'undefined') {
heightBase.data('rotated', self.UA.Rotated);
}
h = heightBase.height() * (mt[1] / 100) - heightBase.data('marginToMyNode');
heightBase.off('resize.' + self.namespace, heightBase.data('fitToBaseFunc'));
fit && heightBase.on('resize.' + self.namespace, heightBase.data('fitToBaseFunc'));
}
}
node.css({ width : w, height : parseInt(h) });
size.w = Math.round(node.width());
size.h = Math.round(node.height());
node.data('resizeSize', size);
if (size.w !== prv.w || size.h !== prv.h) {
node.trigger('resize');
this.trigger('resize', {width : size.w, height : size.h});
}
};
/**
* Restore elfinder node size
*
* @return elFinder
*/
this.restoreSize = function() {
this.resize(width, height);
};
this.show = function() {
node.show();
this.enable().trigger('show');
};
this.hide = function() {
if (this.options.enableAlways) {
prevEnabled = enabled;
enabled = false;
}
this.disable();
this.trigger('hide');
node.hide();
};
/**
* Lazy execution function
*
* @param Object function
* @param Number delay
* @param Object options
* @return Object jQuery.Deferred
*/
this.lazy = function(func, delay, opts) {
var busy = function(state) {
var cnt = node.data('lazycnt'),
repaint;
if (state) {
repaint = node.data('lazyrepaint')? false : opts.repaint;
if (! cnt) {
node.data('lazycnt', 1)
.addClass('elfinder-processing');
} else {
node.data('lazycnt', ++cnt);
}
if (repaint) {
node.data('lazyrepaint', true).css('display'); // force repaint
}
} else {
if (cnt && cnt > 1) {
node.data('lazycnt', --cnt);
} else {
repaint = node.data('lazyrepaint');
node.data('lazycnt', 0)
.removeData('lazyrepaint')
.removeClass('elfinder-processing');
repaint && node.css('display'); // force repaint;
self.trigger('lazydone');
}
}
},
dfd = $.Deferred(),
callFunc = function() {
dfd.resolve(func.call(dfd));
busy(false);
};
delay = delay || 0;
opts = opts || {};
busy(true);
if (delay) {
setTimeout(callFunc, delay);
} else {
requestAnimationFrame(callFunc);
}
return dfd;
};
/**
* Destroy this elFinder instance
*
* @return void
**/
this.destroy = function() {
if (node && node[0].elfinder) {
node.hasClass('elfinder-fullscreen') && self.toggleFullscreen(node);
this.options.syncStart = false;
this.autoSync('forcestop');
this.trigger('destroy').disable();
clipboard = [];
selected = [];
listeners = {};
shortcuts = {};
$(window).off('.' + namespace);
$(document).off('.' + namespace);
self.trigger = function(){};
$(beeper).remove();
node.off()
.removeData()
.empty()
.append(prevContent.contents())
.attr('class', prevContent.attr('class'))
.attr('style', prevContent.attr('style'));
delete node[0].elfinder;
// restore kept events
$.each(prevEvents, function(n, arr) {
$.each(arr, function(i, o) {
node.on(o.type + (o.namespace? '.'+o.namespace : ''), o.selector, o.handler);
});
});
}
};
/**
* Start or stop auto sync
*
* @param String|Bool stop
* @return void
*/
this.autoSync = function(mode) {
var sync;
if (self.options.sync >= 1000) {
if (syncInterval) {
clearTimeout(syncInterval);
syncInterval = null;
self.trigger('autosync', {action : 'stop'});
}
if (mode === 'stop') {
++autoSyncStop;
} else {
autoSyncStop = Math.max(0, --autoSyncStop);
}
if (autoSyncStop || mode === 'forcestop' || ! self.options.syncStart) {
return;
}
// run interval sync
sync = function(start){
var timeout;
if (cwdOptions.syncMinMs && (start || syncInterval)) {
start && self.trigger('autosync', {action : 'start'});
timeout = Math.max(self.options.sync, cwdOptions.syncMinMs);
syncInterval && clearTimeout(syncInterval);
syncInterval = setTimeout(function() {
var dosync = true, hash = cwd, cts;
if (cwdOptions.syncChkAsTs && files[hash] && (cts = files[hash].ts)) {
self.request({
data : {cmd : 'info', targets : [hash], compare : cts, reload : 1},
preventDefault : true
})
.done(function(data){
var ts;
dosync = true;
if (data.compare) {
ts = data.compare;
if (ts == cts) {
dosync = false;
}
}
if (dosync) {
self.sync(hash).always(function(){
if (ts) {
// update ts for cache clear etc.
files[hash].ts = ts;
}
sync();
});
} else {
sync();
}
})
.fail(function(error, xhr){
var err = self.parseError(error);
if (err && xhr.status != 0) {
self.error(err);
if (Array.isArray(err) && $.inArray('errOpen', err) !== -1) {
self.request({
data : {cmd : 'open', target : (self.lastDir('') || self.root()), tree : 1, init : 1},
notify : {type : 'open', cnt : 1, hideCnt : true}
});
}
} else {
syncInterval = setTimeout(function() {
sync();
}, timeout);
}
});
} else {
self.sync(cwd, true).always(function(){
sync();
});
}
}, timeout);
}
};
sync(true);
}
};
/**
* Return bool is inside work zone of specific point
*
* @param Number event.pageX
* @param Number event.pageY
* @return Bool
*/
this.insideWorkzone = function(x, y, margin) {
var rectangle = this.getUI('workzone').data('rectangle');
margin = margin || 1;
if (x < rectangle.left + margin
|| x > rectangle.left + rectangle.width + margin
|| y < rectangle.top + margin
|| y > rectangle.top + rectangle.height + margin) {
return false;
}
return true;
};
/**
* Target ui node move to last of children of elFinder node fot to show front
*
* @param Object target Target jQuery node object
*/
this.toFront = function(target) {
var nodes = node.children('.ui-front').removeClass('elfinder-frontmost'),
lastnode = nodes.last();
nodes.css('z-index', '');
$(target).addClass('ui-front elfinder-frontmost').css('z-index', lastnode.css('z-index') + 1);
};
/**
* Remove class 'elfinder-frontmost' and hide() to target ui node
*
* @param Object target Target jQuery node object
* @param Boolean nohide Do not hide
*/
this.toHide =function(target, nohide) {
var tgt = $(target),
last;
!nohide && tgt.hide();
if (tgt.hasClass('elfinder-frontmost')) {
tgt.removeClass('elfinder-frontmost');
last = node.children('.ui-front:visible:not(.elfinder-frontmost)').last();
if (last.length) {
requestAnimationFrame(function() {
if (!node.children('.elfinder-frontmost:visible').length) {
self.toFront(last);
last.trigger('frontmost');
}
});
}
}
};
/**
* Return css object for maximize
*
* @return Object
*/
this.getMaximizeCss = function() {
return {
width : '100%',
height : '100%',
margin : 0,
top : 0,
left : 0,
display : 'block',
position: 'fixed',
zIndex : Math.max(self.zIndex? (self.zIndex + 1) : 0 , 1000),
maxWidth : '',
maxHeight: ''
};
};
// Closure for togglefullscreen
(function() {
// check is in iframe
if (inFrame && self.UA.Fullscreen) {
self.UA.Fullscreen = false;
if (parentIframe && typeof parentIframe.attr('allowfullscreen') !== 'undefined') {
self.UA.Fullscreen = true;
}
}
var orgStyle, bodyOvf, resizeTm, fullElm, exitFull, toFull,
cls = 'elfinder-fullscreen',
clsN = 'elfinder-fullscreen-native',
checkDialog = function() {
var t = 0,
l = 0;
$.each(node.children('.ui-dialog,.ui-draggable'), function(i, d) {
var $d = $(d),
pos = $d.position();
if (pos.top < 0) {
$d.css('top', t);
t += 20;
}
if (pos.left < 0) {
$d.css('left', l);
l += 20;
}
});
},
funcObj = self.UA.Fullscreen? {
// native full screen mode
fullElm: function() {
return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement || null;
},
exitFull: function() {
if (document.exitFullscreen) {
return document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
return document.webkitExitFullscreen();
} else if (document.mozCancelFullScreen) {
return document.mozCancelFullScreen();
} else if (document.msExitFullscreen) {
return document.msExitFullscreen();
}
},
toFull: function(elem) {
if (elem.requestFullscreen) {
return elem.requestFullscreen();
} else if (elem.webkitRequestFullscreen) {
return elem.webkitRequestFullscreen();
} else if (elem.mozRequestFullScreen) {
return elem.mozRequestFullScreen();
} else if (elem.msRequestFullscreen) {
return elem.msRequestFullscreen();
}
return false;
}
} : {
// node element maximize mode
fullElm: function() {
var full;
if (node.hasClass(cls)) {
return node.get(0);
} else {
full = node.find('.' + cls);
if (full.length) {
return full.get(0);
}
}
return null;
},
exitFull: function() {
var elm;
$(window).off('resize.' + namespace, resize);
if (bodyOvf !== void(0)) {
$('body').css('overflow', bodyOvf);
}
bodyOvf = void(0);
if (orgStyle) {
elm = orgStyle.elm;
restoreStyle(elm);
$(elm).trigger('resize', {fullscreen: 'off'});
}
$(window).trigger('resize');
},
toFull: function(elem) {
bodyOvf = $('body').css('overflow') || '';
$('body').css('overflow', 'hidden');
$(elem).css(self.getMaximizeCss())
.addClass(cls)
.trigger('resize', {fullscreen: 'on'});
checkDialog();
$(window).on('resize.' + namespace, resize).trigger('resize');
return true;
}
},
restoreStyle = function(elem) {
if (orgStyle && orgStyle.elm == elem) {
$(elem).removeClass(cls + ' ' + clsN).attr('style', orgStyle.style);
orgStyle = null;
}
},
resize = function(e) {
var elm;
if (e.target === window) {
resizeTm && cancelAnimationFrame(resizeTm);
resizeTm = requestAnimationFrame(function() {
if (elm = funcObj.fullElm()) {
$(elm).trigger('resize', {fullscreen: 'on'});
}
});
}
};
$(document).on('fullscreenchange.' + namespace + ' webkitfullscreenchange.' + namespace + ' mozfullscreenchange.' + namespace + ' MSFullscreenChange.' + namespace, function(e){
if (self.UA.Fullscreen) {
var elm = funcObj.fullElm(),
win = $(window);
resizeTm && cancelAnimationFrame(resizeTm);
if (elm === null) {
win.off('resize.' + namespace, resize);
if (orgStyle) {
elm = orgStyle.elm;
restoreStyle(elm);
$(elm).trigger('resize', {fullscreen: 'off'});
}
} else {
$(elm).addClass(cls + ' ' + clsN)
.attr('style', 'width:100%; height:100%; margin:0; padding:0;')
.trigger('resize', {fullscreen: 'on'});
win.on('resize.' + namespace, resize);
checkDialog();
}
win.trigger('resize');
}
});
/**
* Toggle Full Scrren Mode
*
* @param Object target
* @param Bool full
* @return Object | Null DOM node object of current full scrren
*/
self.toggleFullscreen = function(target, full) {
var elm = $(target).get(0),
curElm = null;
curElm = funcObj.fullElm();
if (curElm) {
if (curElm == elm) {
if (full === true) {
return curElm;
}
} else {
if (full === false) {
return curElm;
}
}
funcObj.exitFull();
return null;
} else {
if (full === false) {
return null;
}
}
orgStyle = {elm: elm, style: $(elm).attr('style')};
if (funcObj.toFull(elm) !== false) {
return elm;
} else {
orgStyle = null;
return null;
}
};
})();
// Closure for toggleMaximize
(function(){
var cls = 'elfinder-maximized',
resizeTm,
resize = function(e) {
if (e.target === window && e.data && e.data.elm) {
var elm = e.data.elm;
resizeTm && cancelAnimationFrame(resizeTm);
resizeTm = requestAnimationFrame(function() {
elm.trigger('resize', {maximize: 'on'});
});
}
},
exitMax = function(elm) {
$(window).off('resize.' + namespace, resize);
$('body').css('overflow', elm.data('bodyOvf'));
elm.removeClass(cls)
.attr('style', elm.data('orgStyle'))
.removeData('bodyOvf')
.removeData('orgStyle');
elm.trigger('resize', {maximize: 'off'});
},
toMax = function(elm) {
elm.data('bodyOvf', $('body').css('overflow') || '')
.data('orgStyle', elm.attr('style'))
.addClass(cls)
.css(self.getMaximizeCss());
$('body').css('overflow', 'hidden');
$(window).on('resize.' + namespace, {elm: elm}, resize);
elm.trigger('resize', {maximize: 'on'});
};
/**
* Toggle Maximize target node
*
* @param Object target
* @param Bool max
* @return void
*/
self.toggleMaximize = function(target, max) {
var elm = $(target),
maximized = elm.hasClass(cls);
if (maximized) {
if (max === true) {
return;
}
exitMax(elm);
} else {
if (max === false) {
return;
}
toMax(elm);
}
};
})();
/************* init stuffs ****************/
Object.assign($.ui.keyCode, {
'F1' : 112,
'F2' : 113,
'F3' : 114,
'F4' : 115,
'F5' : 116,
'F6' : 117,
'F7' : 118,
'F8' : 119,
'F9' : 120,
'F10' : 121,
'F11' : 122,
'F12' : 123,
'DIG0' : 48,
'DIG1' : 49,
'DIG2' : 50,
'DIG3' : 51,
'DIG4' : 52,
'DIG5' : 53,
'DIG6' : 54,
'DIG7' : 55,
'DIG8' : 56,
'DIG9' : 57,
'NUM0' : 96,
'NUM1' : 97,
'NUM2' : 98,
'NUM3' : 99,
'NUM4' : 100,
'NUM5' : 101,
'NUM6' : 102,
'NUM7' : 103,
'NUM8' : 104,
'NUM9' : 105,
'CONTEXTMENU' : 93,
'DOT' : 190
});
this.dragUpload = false;
this.xhrUpload = (typeof XMLHttpRequestUpload != 'undefined' || typeof XMLHttpRequestEventTarget != 'undefined') && typeof File != 'undefined' && typeof FormData != 'undefined';
// configure transport object
this.transport = {};
if (typeof(this.options.transport) == 'object') {
this.transport = this.options.transport;
if (typeof(this.transport.init) == 'function') {
this.transport.init(this);
}
}
if (typeof(this.transport.send) != 'function') {
this.transport.send = function(opts) {
if (!self.UA.IE) {
// keep native xhr object for handling property responseURL
opts._xhr = new XMLHttpRequest();
opts.xhr = function() { return opts._xhr; };
}
return $.ajax(opts);
};
}
if (this.transport.upload == 'iframe') {
this.transport.upload = $.proxy(this.uploads.iframe, this);
} else if (typeof(this.transport.upload) == 'function') {
this.dragUpload = !!this.options.dragUploadAllow;
} else if (this.xhrUpload && !!this.options.dragUploadAllow) {
this.transport.upload = $.proxy(this.uploads.xhr, this);
this.dragUpload = true;
} else {
this.transport.upload = $.proxy(this.uploads.iframe, this);
}
/**
* Decoding 'raw' string converted to unicode
*
* @param String str
* @return String
*/
this.decodeRawString = function(str) {
var charCodes = function(str) {
var i, len, arr;
for (i=0,len=str.length,arr=[]; i<len; i++) {
arr.push(str.charCodeAt(i));
}
return arr;
},
scalarValues = function(arr) {
var scalars = [], i, len, c;
if (typeof arr === 'string') {arr = charCodes(arr);}
for (i=0,len=arr.length; c=arr[i],i<len; i++) {
if (c >= 0xd800 && c <= 0xdbff) {
scalars.push((c & 1023) + 64 << 10 | arr[++i] & 1023);
} else {
scalars.push(c);
}
}
return scalars;
},
decodeUTF8 = function(arr) {
var i, len, c, str, char = String.fromCharCode;
for (i=0,len=arr.length,str=""; c=arr[i],i<len; i++) {
if (c <= 0x7f) {
str += char(c);
} else if (c <= 0xdf && c >= 0xc2) {
str += char((c&31)<<6 | arr[++i]&63);
} else if (c <= 0xef && c >= 0xe0) {
str += char((c&15)<<12 | (arr[++i]&63)<<6 | arr[++i]&63);
} else if (c <= 0xf7 && c >= 0xf0) {
str += char(
0xd800 | ((c&7)<<8 | (arr[++i]&63)<<2 | arr[++i]>>>4&3) - 64,
0xdc00 | (arr[i++]&15)<<6 | arr[i]&63
);
} else {
str += char(0xfffd);
}
}
return str;
};
return decodeUTF8(scalarValues(str));
};
/**
* Gets target file contents by file.hash
*
* @param String hash The hash
* @param String responseType 'blob' or 'arraybuffer' (default)
* @return arraybuffer|blob The contents.
*/
this.getContents = function(hash, responseType) {
var self = this,
dfd = $.Deferred(),
type = responseType || 'arraybuffer',
url, req;
dfd.fail(function() {
req && req.state() === 'pending' && req.reject();
});
url = self.openUrl(hash);
if (!self.isSameOrigin(url)) {
url = self.openUrl(hash, true);
}
req = self.request({
data : {cmd : 'get'},
options : {
url: url,
type: 'get',
cache : true,
dataType : 'binary',
responseType : type,
processData: false
}
})
.fail(function() {
dfd.reject();
})
.done(function(data) {
dfd.resolve(data);
});
return dfd;
};
this.getMimetype = function(name, orgMime) {
var mime = orgMime,
ext, m;
m = (name + '').match(/\.([^.]+)$/);
if (m && (ext = m[1])) {
if (!extToMimeTable) {
extToMimeTable = self.arrayFlip(self.mimeTypes);
}
if (!(mime = extToMimeTable[ext.toLowerCase()])) {
mime = orgMime;
}
}
return mime;
};
/**
* Supported check hash algorisms
*
* @type Array
*/
self.hashCheckers = [];
/**
* Closure of getContentsHashes()
*/
(function(self) {
var hashLibs = {
check : true
},
md5Calc = function(arr) {
var spark = new hashLibs.SparkMD5.ArrayBuffer(),
job;
job = self.asyncJob(function(buf) {
spark.append(buf);
}, arr).done(function() {
job._md5 = spark.end();
});
return job;
},
shaCalc = function(arr, length) {
var sha, job;
try {
sha = new hashLibs.jsSHA('SHA' + (length.substr(0, 1) === '3'? length : ('-' + length)), 'ARRAYBUFFER');
job = self.asyncJob(function(buf) {
sha.update(buf);
}, arr).done(function() {
job._sha = sha.getHash('HEX');
});
} catch(e) {
job = $.Deferred.reject();
}
return job;
};
// make fm.hashCheckers
if (self.options.cdns.sparkmd5) {
self.hashCheckers.push('md5');
}
if (self.options.cdns.jssha) {
self.hashCheckers = self.hashCheckers.concat(['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512', 'shake128', 'shake256']);
}
/**
* Gets the contents hashes.
*
* @param String target target file.hash
* @param Object needHashes need hash lib names
* @return Object hashes with lib name as key
*/
self.getContentsHashes = function(target, needHashes) {
var dfd = $.Deferred(),
needs = self.arrayFlip(needHashes || ['md5'], true),
libs = [],
jobs = [],
res = {},
req;
dfd.fail(function() {
req && req.reject();
});
if (hashLibs.check) {
delete hashLibs.check;
// load SparkMD5
var libsmd5 = $.Deferred();
if (window.ArrayBuffer && self.options.cdns.sparkmd5) {
libs.push(libsmd5);
self.loadScript([self.options.cdns.sparkmd5],
function(res) {
var SparkMD5 = res || window.SparkMD5;
window.SparkMD5 && delete window.SparkMD5;
libsmd5.resolve();
if (SparkMD5) {
hashLibs.SparkMD5 = SparkMD5;
}
},
{
tryRequire: true,
error: function() {
libsmd5.reject();
}
}
);
}
// load jsSha
var libssha = $.Deferred();
if (window.ArrayBuffer && self.options.cdns.jssha) {
libs.push(libssha);
self.loadScript([self.options.cdns.jssha],
function(res) {
var jsSHA = res || window.jsSHA;
window.jsSHA && delete window.jsSHA;
libssha.resolve();
if (jsSHA) {
hashLibs.jsSHA = jsSHA;
}
},
{
tryRequire: true,
error: function() {
libssha.reject();
}
}
);
}
}
$.when.apply(null, libs).always(function() {
if (Object.keys(hashLibs).length) {
req = self.getContents(target).done(function(arrayBuffer) {
var arr = (arrayBuffer instanceof ArrayBuffer && arrayBuffer.byteLength > 0)? self.sliceArrayBuffer(arrayBuffer, 1048576) : false,
i;
if (needs.md5 && hashLibs.SparkMD5) {
jobs.push(function() {
var job = md5Calc(arr).done(function() {
var f;
res.md5 = job._md5;
if (f = self.file(target)) {
f.md5 = job._md5;
}
dfd.notify(res);
});
dfd.fail(function() {
job.reject();
});
return job;
});
}
if (hashLibs.jsSHA) {
$.each(['1', '224', '256', '384', '512', '3-224', '3-256', '3-384', '3-512', 'ke128', 'ke256'], function(i, v) {
if (needs['sha' + v]) {
jobs.push(function() {
var job = shaCalc(arr, v).done(function() {
var f;
res['sha' + v] = job._sha;
if (f = self.file(target)) {
f['sha' + v] = job._sha;
}
dfd.notify(res);
});
return job;
});
}
});
}
if (jobs.length) {
self.sequence(jobs).always(function() {
dfd.resolve(res);
});
} else {
dfd.reject();
}
}).fail(function() {
dfd.reject();
});
} else {
dfd.reject();
}
});
return dfd;
};
})(this);
/**
* Parse error value to display
*
* @param Mixed error
* @return Mixed parsed error
*/
this.parseError = function(error) {
var arg = error;
if ($.isPlainObject(arg)) {
arg = arg.error;
}
return arg;
};
/**
* Alias for this.trigger('error', {error : 'message'})
*
* @param String error message
* @return elFinder
**/
this.error = function() {
var arg = arguments[0],
opts = arguments[1] || null,
err;
if (arguments.length == 1 && typeof(arg) === 'function') {
return self.bind('error', arg);
} else {
err = this.parseError(arg);
return (err === true || !err)? this : self.trigger('error', {error: err, opts : opts});
}
};
// create bind/trigger aliases for build-in events
$.each(events, function(i, name) {
self[name] = function() {
var arg = arguments[0];
return arguments.length == 1 && typeof(arg) == 'function'
? self.bind(name, arg)
: self.trigger(name, $.isPlainObject(arg) ? arg : {});
};
});
// bind core event handlers
this
.enable(function() {
if (!enabled && self.api && self.visible() && self.ui.overlay.is(':hidden') && ! node.children('.elfinder-dialog.' + self.res('class', 'editing') + ':visible').length) {
enabled = true;
document.activeElement && document.activeElement.blur();
node.removeClass('elfinder-disabled');
}
})
.disable(function() {
prevEnabled = enabled;
enabled = false;
node.addClass('elfinder-disabled');
})
.open(function() {
selected = [];
})
.select(function(e) {
var cnt = 0,
unselects = [];
selected = $.grep(e.data.selected || e.data.value|| [], function(hash) {
if (unselects.length || (self.maxTargets && ++cnt > self.maxTargets)) {
unselects.push(hash);
return false;
} else {
return files[hash] ? true : false;
}
});
if (unselects.length) {
self.trigger('unselectfiles', {files: unselects, inselect: true});
self.toast({mode: 'warning', msg: self.i18n(['errMaxTargets', self.maxTargets])});
}
})
.error(function(e) {
var opts = {
cssClass : 'elfinder-dialog-error',
title : self.i18n(self.i18n('error')),
resizable : false,
destroyOnClose : true,
buttons : {}
};
opts.buttons[self.i18n(self.i18n('btnClose'))] = function() { $(this).elfinderdialog('close'); };
if (e.data.opts && $.isPlainObject(e.data.opts)) {
Object.assign(opts, e.data.opts);
}
self.dialog('<span class="elfinder-dialog-icon elfinder-dialog-icon-error"/>'+self.i18n(e.data.error), opts);
})
.bind('tmb', function(e) {
$.each(e.data.images||[], function(hash, tmb) {
if (files[hash]) {
files[hash].tmb = tmb;
}
});
})
.bind('searchstart', function(e) {
Object.assign(self.searchStatus, e.data);
self.searchStatus.state = 1;
})
.bind('search', function(e) {
self.searchStatus.state = 2;
})
.bind('searchend', function() {
self.searchStatus.state = 0;
self.searchStatus.ininc = false;
self.searchStatus.mixed = false;
})
.bind('canMakeEmptyFile', function(e) {
var data = e.data,
obj = {};
if (data && Array.isArray(data.mimes)) {
if (!data.unshift) {
obj = self.mimesCanMakeEmpty;
}
$.each(data.mimes, function() {
if (!obj[this]) {
obj[this] = self.mimeTypes[this];
}
});
if (data.unshift) {
self.mimesCanMakeEmpty = Object.assign(obj, self.mimesCanMakeEmpty);
}
}
})
.bind('themechange', function() {
requestAnimationFrame(function() {
self.trigger('uiresize');
});
})
;
// We listen and emit a sound on delete according to option
if (true === this.options.sound) {
this.bind('playsound', function(e) {
var play = beeper.canPlayType && beeper.canPlayType('audio/wav; codecs="1"'),
file = e.data && e.data.soundFile;
play && file && play != '' && play != 'no' && $(beeper).html('<source src="' + soundPath + file + '" type="audio/wav">')[0].play();
});
}
// bind external event handlers
$.each(this.options.handlers, function(event, callback) {
self.bind(event, callback);
});
/**
* History object. Store visited folders
*
* @type Object
**/
this.history = new this.history(this);
/**
* Root hashed
*
* @type Object
*/
this.roots = {};
/**
* leaf roots
*
* @type Object
*/
this.leafRoots = {};
this.volumeExpires = {};
/**
* Loaded commands
*
* @type Object
**/
this._commands = {};
if (!Array.isArray(this.options.commands)) {
this.options.commands = [];
}
if ($.inArray('*', this.options.commands) !== -1) {
this.options.commands = Object.keys(this.commands);
}
/**
* UI command map of cwd volume ( That volume driver option `uiCmdMap` )
*
* @type Object
**/
this.commandMap = {};
/**
* cwd options of each volume
* key: volumeid
* val: options object
*
* @type Object
*/
this.volOptions = {};
/**
* Has volOptions data
*
* @type Boolean
*/
this.hasVolOptions = false;
/**
* Hash of trash holders
* key: trash folder hash
* val: source volume hash
*
* @type Object
*/
this.trashes = {};
/**
* cwd options of each folder/file
* key: hash
* val: options object
*
* @type Object
*/
this.optionsByHashes = {};
/**
* UI Auto Hide Functions
* Each auto hide function mast be call to `fm.trigger('uiautohide')` at end of process
*
* @type Array
**/
this.uiAutoHide = [];
// trigger `uiautohide`
this.one('open', function() {
if (self.uiAutoHide.length) {
setTimeout(function() {
self.trigger('uiautohide');
}, 500);
}
});
// Auto Hide Functions sequential processing start
this.bind('uiautohide', function() {
if (self.uiAutoHide.length) {
self.uiAutoHide.shift()();
}
});
if (this.options.width) {
width = this.options.width;
}
if (this.options.height) {
height = this.options.height;
}
if (this.options.heightBase) {
heightBase = $(this.options.heightBase);
}
if (this.options.soundPath) {
soundPath = this.options.soundPath.replace(/\/+$/, '') + '/';
} else {
soundPath = this.baseUrl + soundPath;
}
self.one('opendone', function() {
var tm;
// attach events to document
$(document)
// disable elfinder on click outside elfinder
.on('click.'+namespace, function(e) { enabled && ! self.options.enableAlways && !$(e.target).closest(node).length && self.disable(); })
// exec shortcuts
.on(keydown+' '+keypress+' '+keyup+' '+mousedown, execShortcut);
// attach events to window
self.options.useBrowserHistory && $(window)
.on('popstate.' + namespace, function(ev) {
var state = ev.originalEvent.state || {},
hasThash = state.thash? true : false,
dialog = node.find('.elfinder-frontmost:visible'),
input = node.find('.elfinder-navbar-dir,.elfinder-cwd-filename').find('input,textarea'),
onOpen, toast;
if (!hasThash) {
state = { thash: self.cwd().hash };
// scroll to elFinder node
$('html,body').animate({ scrollTop: node.offset().top });
}
if (dialog.length || input.length) {
history.pushState(state, null, location.pathname + location.search + '#elf_' + state.thash);
if (dialog.length) {
if (!dialog.hasClass(self.res('class', 'preventback'))) {
if (dialog.hasClass('elfinder-contextmenu')) {
$(document).trigger($.Event('keydown', { keyCode: $.ui.keyCode.ESCAPE, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false }));
} else if (dialog.hasClass('elfinder-dialog')) {
dialog.elfinderdialog('close');
} else {
dialog.trigger('close');
}
}
} else {
input.trigger($.Event('keydown', { keyCode: $.ui.keyCode.ESCAPE, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false }));
}
} else {
if (hasThash) {
!$.isEmptyObject(self.files()) && self.request({
data : {cmd : 'open', target : state.thash, onhistory : 1},
notify : {type : 'open', cnt : 1, hideCnt : true},
syncOnFail : true
});
} else {
onOpen = function() {
toast.trigger('click');
};
self.one('open', onOpen, true);
toast = self.toast({
msg: self.i18n('pressAgainToExit'),
onHidden: function() {
self.unbind('open', onOpen);
history.pushState(state, null, location.pathname + location.search + '#elf_' + state.thash);
}
});
}
}
});
$(window).on('resize.' + namespace, function(e){
if (e.target === this) {
tm && cancelAnimationFrame(tm);
tm = requestAnimationFrame(function() {
var prv = node.data('resizeSize') || {w: 0, h: 0},
size = {w: Math.round(node.width()), h: Math.round(node.height())};
node.data('resizeSize', size);
if (size.w !== prv.w || size.h !== prv.h) {
node.trigger('resize');
self.trigger('resize', {width : size.w, height : size.h});
}
});
}
})
.on('beforeunload.' + namespace,function(e){
var msg, cnt;
if (node.is(':visible')) {
if (self.ui.notify.children().length && $.inArray('hasNotifyDialog', self.options.windowCloseConfirm) !== -1) {
msg = self.i18n('ntfsmth');
} else if (node.find('.'+self.res('class', 'editing')).length && $.inArray('editingFile', self.options.windowCloseConfirm) !== -1) {
msg = self.i18n('editingFile');
} else if ((cnt = Object.keys(self.selected()).length) && $.inArray('hasSelectedItem', self.options.windowCloseConfirm) !== -1) {
msg = self.i18n('hasSelected', ''+cnt);
} else if ((cnt = Object.keys(self.clipboard()).length) && $.inArray('hasClipboardData', self.options.windowCloseConfirm) !== -1) {
msg = self.i18n('hasClipboard', ''+cnt);
}
if (msg) {
e.returnValue = msg;
return msg;
}
}
self.trigger('unload');
});
// bind window onmessage for CORS
$(window).on('message.' + namespace, function(e){
var res = e.originalEvent || null,
obj, data;
if (res && self.uploadURL.indexOf(res.origin) === 0) {
try {
obj = JSON.parse(res.data);
data = obj.data || null;
if (data) {
if (data.error) {
if (obj.bind) {
self.trigger(obj.bind+'fail', data);
}
self.error(data.error);
} else {
data.warning && self.error(data.warning);
self.updateCache(data);
data.removed && data.removed.length && self.remove(data);
data.added && data.added.length && self.add(data);
data.changed && data.changed.length && self.change(data);
if (obj.bind) {
self.trigger(obj.bind, data);
self.trigger(obj.bind+'done');
}
data.sync && self.sync();
}
}
} catch (e) {
self.sync();
}
}
});
// elFinder enable always
if (self.options.enableAlways) {
$(window).on('focus.' + namespace, function(e){
(e.target === this) && self.enable();
});
if (inFrame) {
$(window.top).on('focus.' + namespace, function() {
if (self.enable() && (! parentIframe || parentIframe.is(':visible'))) {
requestAnimationFrame(function() {
$(window).trigger('focus');
});
}
});
}
} else if (inFrame) {
$(window).on('blur.' + namespace, function(e){
enabled && e.target === this && self.disable();
});
}
// return focus to the window on click (elFInder in the frame)
if (inFrame) {
node.on('click', function(e) {
$(window).trigger('focus');
});
}
// elFinder to enable by mouse over
if (self.options.enableByMouseOver) {
node.on('mouseenter touchstart', function(e) {
(inFrame) && $(window).trigger('focus');
! self.enabled() && self.enable();
});
}
});
// store instance in node
node[0].elfinder = this;
// auto load language file
dfrdsBeforeBootup.push((function() {
var lang = self.lang,
langJs = self.i18nBaseUrl + 'elfinder.' + lang + '.js',
dfd = $.Deferred().done(function() {
if (self.i18[lang]) {
self.lang = lang;
}
self.trigger('i18load');
i18n = self.lang === 'en'
? self.i18['en']
: $.extend(true, {}, self.i18['en'], self.i18[self.lang]);
});
if (!self.i18[lang]) {
self.lang = 'en';
if (self.hasRequire) {
require([langJs], function() {
dfd.resolve();
}, function() {
dfd.resolve();
});
} else {
self.loadScript([langJs], function() {
dfd.resolve();
}, {
loadType: 'tag',
error : function() {
dfd.resolve();
}
});
}
} else {
dfd.resolve();
}
return dfd;
})());
// elFinder boot up function
bootUp = function() {
var columnNames;
/**
* i18 messages
*
* @type Object
**/
self.messages = i18n.messages;
// check jquery ui
if (!($.fn.selectable && $.fn.draggable && $.fn.droppable && $.fn.resizable && $.fn.slider)) {
return alert(self.i18n('errJqui'));
}
// check node
if (!node.length) {
return alert(self.i18n('errNode'));
}
// check connector url
if (!self.options.url) {
return alert(self.i18n('errURL'));
}
// column key/name map for fm.getColumnName()
columnNames = Object.assign({
name : self.i18n('name'),
perm : self.i18n('perms'),
date : self.i18n('modify'),
size : self.i18n('size'),
kind : self.i18n('kind'),
modestr : self.i18n('mode'),
modeoct : self.i18n('mode'),
modeboth : self.i18n('mode')
}, self.options.uiOptions.cwd.listView.columnsCustomName);
/**
* Gets the column name of cwd list view
*
* @param String key The key
* @return String The column name.
*/
self.getColumnName = function(key) {
return columnNames[key] || self.i18n(key);
};
/**
* Interface direction
*
* @type String
* @default "ltr"
**/
self.direction = i18n.direction;
/**
* Date/time format
*
* @type String
* @default "m.d.Y"
**/
self.dateFormat = self.options.dateFormat || i18n.dateFormat;
/**
* Date format like "Yesterday 10:20:12"
*
* @type String
* @default "{day} {time}"
**/
self.fancyFormat = self.options.fancyDateFormat || i18n.fancyDateFormat;
/**
* Date format for if upload file has not original unique name
* e.g. Clipboard image data, Image data taken with iOS
*
* @type String
* @default "ymd-His"
**/
self.nonameDateFormat = (self.options.nonameDateFormat || i18n.nonameDateFormat).replace(/[\/\\]/g, '_');
/**
* Css classes
*
* @type String
**/
self.cssClass = 'ui-helper-reset ui-helper-clearfix ui-widget ui-widget-content ui-corner-all elfinder elfinder-'
+(self.direction == 'rtl' ? 'rtl' : 'ltr')
+(self.UA.Touch? (' elfinder-touch' + (self.options.resizable ? ' touch-punch' : '')) : '')
+(self.UA.Mobile? ' elfinder-mobile' : '')
+(self.UA.iOS? ' elfinder-ios' : '')
+' '+self.options.cssClass;
// prepare node
node.addClass(self.cssClass)
.on(mousedown, function() {
!enabled && self.enable();
});
// draggable closure
(function() {
var ltr, wzRect, wzBottom, wzBottom2, nodeStyle,
keyEvt = keydown + 'draggable' + ' keyup.' + namespace + 'draggable';
/**
* Base draggable options
*
* @type Object
**/
self.draggable = {
appendTo : node,
addClasses : false,
distance : 4,
revert : true,
refreshPositions : false,
cursor : 'crosshair',
cursorAt : {left : 50, top : 47},
scroll : false,
start : function(e, ui) {
var helper = ui.helper,
targets = $.grep(helper.data('files')||[], function(h) {
if (h) {
remember[h] = true;
return true;
}
return false;
}),
locked = false,
cnt, h;
// fix node size
nodeStyle = node.attr('style');
node.width(node.width()).height(node.height());
// set var for drag()
ltr = (self.direction === 'ltr');
wzRect = self.getUI('workzone').data('rectangle');
wzBottom = wzRect.top + wzRect.height;
wzBottom2 = wzBottom - self.getUI('navdock').outerHeight(true);
self.draggingUiHelper = helper;
cnt = targets.length;
while (cnt--) {
h = targets[cnt];
if (files[h].locked) {
locked = true;
helper.data('locked', true);
break;
}
}
!locked && self.trigger('lockfiles', {files : targets});
helper.data('autoScrTm', setInterval(function() {
if (helper.data('autoScr')) {
self.autoScroll[helper.data('autoScr')](helper.data('autoScrVal'));
}
}, 50));
},
drag : function(e, ui) {
var helper = ui.helper,
autoScr, autoUp, bottom;
if ((autoUp = wzRect.top > e.pageY) || wzBottom2 < e.pageY) {
if (wzRect.cwdEdge > e.pageX) {
autoScr = (ltr? 'navbar' : 'cwd') + (autoUp? 'Up' : 'Down');
} else {
autoScr = (ltr? 'cwd' : 'navbar') + (autoUp? 'Up' : 'Down');
}
if (!autoUp) {
if (autoScr.substr(0, 3) === 'cwd') {
if (wzBottom < e.pageY) {
bottom = wzBottom;
} else {
autoScr = null;
}
} else {
bottom = wzBottom2;
}
}
if (autoScr) {
helper.data('autoScr', autoScr);
helper.data('autoScrVal', Math.pow((autoUp? wzRect.top - e.pageY : e.pageY - bottom), 1.3));
}
}
if (! autoScr) {
if (helper.data('autoScr')) {
helper.data('refreshPositions', 1).data('autoScr', null);
}
}
if (helper.data('refreshPositions') && $(this).elfUiWidgetInstance('draggable')) {
if (helper.data('refreshPositions') > 0) {
$(this).draggable('option', { refreshPositions : true, elfRefresh : true });
helper.data('refreshPositions', -1);
} else {
$(this).draggable('option', { refreshPositions : false, elfRefresh : false });
helper.data('refreshPositions', null);
}
}
},
stop : function(e, ui) {
var helper = ui.helper,
files;
$(document).off(keyEvt);
$(this).elfUiWidgetInstance('draggable') && $(this).draggable('option', { refreshPositions : false });
self.draggingUiHelper = null;
self.trigger('focus').trigger('dragstop');
if (! helper.data('droped')) {
files = $.grep(helper.data('files')||[], function(h) { return h? true : false ;});
self.trigger('unlockfiles', {files : files});
self.trigger('selectfiles', {files : self.selected()});
}
self.enable();
// restore node style
node.attr('style', nodeStyle);
helper.data('autoScrTm') && clearInterval(helper.data('autoScrTm'));
},
helper : function(e, ui) {
var element = this.id ? $(this) : $(this).parents('[id]:first'),
helper = $('<div class="elfinder-drag-helper"><span class="elfinder-drag-helper-icon-status"/></div>'),
icon = function(f) {
var mime = f.mime, i, tmb = self.tmb(f);
i = '<div class="elfinder-cwd-icon elfinder-cwd-icon-drag '+self.mime2class(mime)+' ui-corner-all"/>';
if (tmb) {
i = $(i).addClass(tmb.className).css('background-image', "url('"+tmb.url+"')").get(0).outerHTML;
} else if (f.icon) {
i = $(i).css(self.getIconStyle(f, true)).get(0).outerHTML;
}
if (f.csscls) {
i = '<div class="'+f.csscls+'">' + i + '</div>';
}
return i;
},
hashes, l, ctr;
self.draggingUiHelper && self.draggingUiHelper.stop(true, true);
self.trigger('dragstart', {target : element[0], originalEvent : e}, true);
hashes = element.hasClass(self.res('class', 'cwdfile'))
? self.selected()
: [self.navId2Hash(element.attr('id'))];
helper.append(icon(files[hashes[0]])).data('files', hashes).data('locked', false).data('droped', false).data('namespace', namespace).data('dropover', 0);
if ((l = hashes.length) > 1) {
helper.append(icon(files[hashes[l-1]]) + '<span class="elfinder-drag-num">'+l+'</span>');
}
$(document).on(keyEvt, function(e){
var chk = (e.shiftKey||e.ctrlKey||e.metaKey);
if (ctr !== chk) {
ctr = chk;
if (helper.is(':visible') && helper.data('dropover') && ! helper.data('droped')) {
helper.toggleClass('elfinder-drag-helper-plus', helper.data('locked')? true : ctr);
self.trigger(ctr? 'unlockfiles' : 'lockfiles', {files : hashes, helper: helper});
}
}
});
return helper;
}
};
})();
// in getFileCallback set - change default actions on double click/enter/ctrl+enter
if (self.commands.getfile) {
if (typeof(self.options.getFileCallback) == 'function') {
self.bind('dblclick', function(e) {
e.preventDefault();
self.exec('getfile').fail(function() {
self.exec('open', e.data && e.data.file? [ e.data.file ]: void(0));
});
});
self.shortcut({
pattern : 'enter',
description : self.i18n('cmdgetfile'),
callback : function() { self.exec('getfile').fail(function() { self.exec(self.OS == 'mac' ? 'rename' : 'open'); }); }
})
.shortcut({
pattern : 'ctrl+enter',
description : self.i18n(self.OS == 'mac' ? 'cmdrename' : 'cmdopen'),
callback : function() { self.exec(self.OS == 'mac' ? 'rename' : 'open'); }
});
} else {
self.options.getFileCallback = null;
}
}
// load commands
$.each(self.commands, function(name, cmd) {
var proto = Object.assign({}, cmd.prototype),
extendsCmd, opts;
if ($.isFunction(cmd) && !self._commands[name] && (cmd.prototype.forceLoad || $.inArray(name, self.options.commands) !== -1)) {
extendsCmd = cmd.prototype.extendsCmd || '';
if (extendsCmd) {
if ($.isFunction(self.commands[extendsCmd])) {
cmd.prototype = Object.assign({}, base, new self.commands[extendsCmd](), cmd.prototype);
} else {
return true;
}
} else {
cmd.prototype = Object.assign({}, base, cmd.prototype);
}
self._commands[name] = new cmd();
cmd.prototype = proto;
opts = self.options.commandsOptions[name] || {};
if (extendsCmd && self.options.commandsOptions[extendsCmd]) {
opts = $.extend(true, {}, self.options.commandsOptions[extendsCmd], opts);
}
self._commands[name].setup(name, opts);
// setup linked commands
if (self._commands[name].linkedCmds.length) {
$.each(self._commands[name].linkedCmds, function(i, n) {
var lcmd = self.commands[n];
if ($.isFunction(lcmd) && !self._commands[n]) {
lcmd.prototype = base;
self._commands[n] = new lcmd();
self._commands[n].setup(n, self.options.commandsOptions[n]||{});
}
});
}
}
});
/**
* UI nodes
*
* @type Object
**/
self.ui = {
// container for nav panel and current folder container
workzone : $('<div/>').appendTo(node).elfinderworkzone(self),
// container for folders tree / places
navbar : $('<div/>').appendTo(node).elfindernavbar(self, self.options.uiOptions.navbar || {}),
// container for for preview etc at below the navbar
navdock : $('<div/>').appendTo(node).elfindernavdock(self, self.options.uiOptions.navdock || {}),
// contextmenu
contextmenu : $('<div/>').appendTo(node).elfindercontextmenu(self),
// overlay
overlay : $('<div/>').appendTo(node).elfinderoverlay({
show : function() { self.disable(); },
hide : function() { prevEnabled && self.enable(); }
}),
// current folder container
cwd : $('<div/>').appendTo(node).elfindercwd(self, self.options.uiOptions.cwd || {}),
// notification dialog window
notify : self.dialog('', {
cssClass : 'elfinder-dialog-notify',
position : self.options.notifyDialog.position,
absolute : true,
resizable : false,
autoOpen : false,
closeOnEscape : false,
title : '&nbsp;',
width : self.options.notifyDialog.width? parseInt(self.options.notifyDialog.width) : null,
minHeight : null
}),
statusbar : $('<div class="ui-widget-header ui-helper-clearfix ui-corner-bottom elfinder-statusbar"/>').hide().appendTo(node),
toast : $('<div class="elfinder-toast"/>').appendTo(node),
bottomtray : $('<div class="elfinder-bottomtray">').appendTo(node)
};
self.trigger('uiready');
// load required ui
$.each(self.options.ui || [], function(i, ui) {
var name = 'elfinder'+ui,
opts = self.options.uiOptions[ui] || {};
if (!self.ui[ui] && $.fn[name]) {
// regist to self.ui before make instance
self.ui[ui] = $('<'+(opts.tag || 'div')+'/>').appendTo(node);
self.ui[ui][name](self, opts);
}
});
// update size
self.resize(width, height);
// make node resizable
if (self.options.resizable) {
node.resizable({
resize : function(e, ui) {
self.resize(ui.size.width, ui.size.height);
},
handles : 'se',
minWidth : 300,
minHeight : 200
});
if (self.UA.Touch) {
node.addClass('touch-punch');
}
}
(function() {
var navbar = self.getUI('navbar'),
cwd = self.getUI('cwd').parent();
self.autoScroll = {
navbarUp : function(v) {
navbar.scrollTop(Math.max(0, navbar.scrollTop() - v));
},
navbarDown : function(v) {
navbar.scrollTop(navbar.scrollTop() + v);
},
cwdUp : function(v) {
cwd.scrollTop(Math.max(0, cwd.scrollTop() - v));
},
cwdDown : function(v) {
cwd.scrollTop(cwd.scrollTop() + v);
}
};
})();
// Swipe on the touch devices to show/hide of toolbar or navbar
if (self.UA.Touch) {
(function() {
var lastX, lastY, nodeOffset, nodeWidth, nodeTop, navbarW, toolbarH,
navbar = self.getUI('navbar'),
toolbar = self.getUI('toolbar'),
moveEv = 'touchmove.stopscroll',
moveTm,
moveUpOn = function(e) {
var touches = e.originalEvent.touches || [{}],
y = touches[0].pageY || null;
if (!lastY || y < lastY) {
e.preventDefault();
moveTm && clearTimeout(moveTm);
}
},
moveDownOn = function(e) {
e.preventDefault();
moveTm && clearTimeout(moveTm);
},
moveOff = function() {
moveTm = setTimeout(function() {
node.off(moveEv);
}, 100);
},
handleW, handleH = 50;
navbar = navbar.children().length? navbar : null;
toolbar = toolbar.length? toolbar : null;
node.on('touchstart touchmove touchend', function(e) {
if (e.type === 'touchend') {
lastX = false;
lastY = false;
moveOff();
return;
}
var touches = e.originalEvent.touches || [{}],
x = touches[0].pageX || null,
y = touches[0].pageY || null,
ltr = (self.direction === 'ltr'),
navbarMode, treeWidth, swipeX, moveX, toolbarT, mode;
if (x === null || y === null || (e.type === 'touchstart' && touches.length > 1)) {
return;
}
if (e.type === 'touchstart') {
nodeOffset = node.offset();
nodeWidth = node.width();
if (navbar) {
lastX = false;
if (navbar.is(':hidden')) {
if (! handleW) {
handleW = Math.max(50, nodeWidth / 10);
}
if ((ltr? (x - nodeOffset.left) : (nodeWidth + nodeOffset.left - x)) < handleW) {
lastX = x;
}
} else if (! e.originalEvent._preventSwipeX) {
navbarW = navbar.width();
if (ltr) {
swipeX = (x < nodeOffset.left + navbarW);
} else {
swipeX = (x > nodeOffset.left + nodeWidth - navbarW);
}
if (swipeX) {
handleW = Math.max(50, nodeWidth / 10);
lastX = x;
} else {
lastX = false;
}
}
}
if (toolbar) {
lastY = false;
if (! e.originalEvent._preventSwipeY) {
toolbarH = toolbar.height();
nodeTop = nodeOffset.top;
if (y - nodeTop < (toolbar.is(':hidden')? handleH : (toolbarH + 30))) {
lastY = y;
node.on(moveEv, toolbar.is(':hidden')? moveDownOn: moveUpOn);
}
}
}
} else {
if (navbar && lastX !== false) {
navbarMode = (ltr? (lastX > x) : (lastX < x))? 'navhide' : 'navshow';
moveX = Math.abs(lastX - x);
if (navbarMode === 'navhide' && moveX > navbarW * 0.6
|| (moveX > (navbarMode === 'navhide'? navbarW / 3 : 45)
&& (navbarMode === 'navshow'
|| (ltr? x < nodeOffset.left + 20 : x > nodeOffset.left + nodeWidth - 20)
))
) {
self.getUI('navbar').trigger(navbarMode, {handleW: handleW});
lastX = false;
}
}
if (toolbar && lastY !== false ) {
toolbarT = toolbar.offset().top;
if (Math.abs(lastY - y) > Math.min(45, toolbarH / 3)) {
mode = (lastY > y)? 'slideUp' : 'slideDown';
if (mode === 'slideDown' || toolbarT + 20 > y) {
if (toolbar.is(mode === 'slideDown' ? ':hidden' : ':visible')) {
toolbar.stop(true, true).trigger('toggle', {duration: 100, handleH: handleH});
}
lastY = false;
}
}
}
}
});
})();
}
if (self.dragUpload) {
// add event listener for HTML5 DnD upload
(function() {
var isin = function(e) {
return (e.target.nodeName !== 'TEXTAREA' && e.target.nodeName !== 'INPUT' && $(e.target).closest('div.ui-dialog-content').length === 0);
},
ent = 'native-drag-enter',
disable = 'native-drag-disable',
c = 'class',
navdir = self.res(c, 'navdir'),
droppable = self.res(c, 'droppable'),
dropover = self.res(c, 'adroppable'),
arrow = self.res(c, 'navarrow'),
clDropActive = self.res(c, 'adroppable'),
wz = self.getUI('workzone'),
ltr = (self.direction === 'ltr'),
clearTm = function() {
autoScrTm && cancelAnimationFrame(autoScrTm);
autoScrTm = null;
},
wzRect, autoScrFn, autoScrTm;
node.on('dragenter', function(e) {
clearTm();
if (isin(e)) {
e.preventDefault();
e.stopPropagation();
wzRect = wz.data('rectangle');
}
})
.on('dragleave', function(e) {
clearTm();
if (isin(e)) {
e.preventDefault();
e.stopPropagation();
}
})
.on('dragover', function(e) {
var autoUp;
if (isin(e)) {
e.preventDefault();
e.stopPropagation();
e.originalEvent.dataTransfer.dropEffect = 'none';
if (! autoScrTm) {
autoScrTm = requestAnimationFrame(function() {
var wzBottom = wzRect.top + wzRect.height,
wzBottom2 = wzBottom - self.getUI('navdock').outerHeight(true),
fn;
if ((autoUp = e.pageY < wzRect.top) || e.pageY > wzBottom2 ) {
if (wzRect.cwdEdge > e.pageX) {
fn = (ltr? 'navbar' : 'cwd') + (autoUp? 'Up' : 'Down');
} else {
fn = (ltr? 'cwd' : 'navbar') + (autoUp? 'Up' : 'Down');
}
if (!autoUp) {
if (fn.substr(0, 3) === 'cwd') {
if (wzBottom < e.pageY) {
wzBottom2 = wzBottom;
} else {
fn = '';
}
}
}
fn && self.autoScroll[fn](Math.pow((autoUp? wzRect.top - e.pageY : e.pageY - wzBottom2), 1.3));
}
autoScrTm = null;
});
}
} else {
clearTm();
}
})
.on('drop', function(e) {
clearTm();
if (isin(e)) {
e.stopPropagation();
e.preventDefault();
}
});
node.on('dragenter', '.native-droppable', function(e){
if (e.originalEvent.dataTransfer) {
var $elm = $(e.currentTarget),
id = e.currentTarget.id || null,
cwd = null,
elfFrom;
if (!id) { // target is cwd
cwd = self.cwd();
$elm.data(disable, false);
try {
$.each(e.originalEvent.dataTransfer.types, function(i, v){
if (v.substr(0, 13) === 'elfinderfrom:') {
elfFrom = v.substr(13).toLowerCase();
}
});
} catch(e) {}
}
if (!cwd || (cwd.write && (!elfFrom || elfFrom !== (window.location.href + cwd.hash).toLowerCase()))) {
e.preventDefault();
e.stopPropagation();
$elm.data(ent, true);
$elm.addClass(clDropActive);
} else {
$elm.data(disable, true);
}
}
})
.on('dragleave', '.native-droppable', function(e){
if (e.originalEvent.dataTransfer) {
var $elm = $(e.currentTarget);
e.preventDefault();
e.stopPropagation();
if ($elm.data(ent)) {
$elm.data(ent, false);
} else {
$elm.removeClass(clDropActive);
}
}
})
.on('dragover', '.native-droppable', function(e){
if (e.originalEvent.dataTransfer) {
var $elm = $(e.currentTarget);
e.preventDefault();
e.stopPropagation();
e.originalEvent.dataTransfer.dropEffect = $elm.data(disable)? 'none' : 'copy';
$elm.data(ent, false);
}
})
.on('drop', '.native-droppable', function(e){
if (e.originalEvent && e.originalEvent.dataTransfer) {
var $elm = $(e.currentTarget),
id;
e.preventDefault();
e.stopPropagation();
$elm.removeClass(clDropActive);
if (e.currentTarget.id) {
id = $elm.hasClass(navdir)? self.navId2Hash(e.currentTarget.id) : self.cwdId2Hash(e.currentTarget.id);
} else {
id = self.cwd().hash;
}
e.originalEvent._target = id;
self.exec('upload', {dropEvt: e.originalEvent, target: id}, void 0, id);
}
});
})();
}
// trigger event cssloaded if cddAutoLoad disabled
if (self.cssloaded === null) {
// check css loaded and remove hide
(function() {
var loaded = function() {
if (node.data('cssautoloadHide')) {
node.data('cssautoloadHide').remove();
node.removeData('cssautoloadHide');
}
self.cssloaded = true;
requestAnimationFrame(function() {
self.trigger('cssloaded');
});
},
cnt, fi;
if (node.css('visibility') === 'hidden') {
cnt = 1000; // timeout 10 secs
fi = setInterval(function() {
if (--cnt < 0 || node.css('visibility') !== 'hidden') {
clearInterval(fi);
loaded();
}
}, 10);
} else {
loaded();
}
})();
} else {
self.cssloaded = true;
self.trigger('cssloaded');
}
// calculate elFinder node z-index
self.zIndexCalc();
// send initial request and start to pray >_<
self.trigger('init')
.request({
data : {cmd : 'open', target : self.startDir(), init : 1, tree : 1},
preventDone : true,
notify : {type : 'open', cnt : 1, hideCnt : true},
freeze : true
})
.fail(function() {
self.trigger('fail').disable().lastDir('');
listeners = {};
shortcuts = {};
$(document).add(node).off('.'+namespace);
self.trigger = function() { };
})
.done(function(data) {
var trashDisable = function(th) {
var src = self.file(self.trashes[th]),
d = self.options.debug,
error;
if (src && src.volumeid) {
delete self.volOptions[src.volumeid].trashHash;
}
self.trashes[th] = false;
self.debug('backend-error', 'Trash hash "'+th+'" was not found or not writable.');
},
toChkTh = {};
// regist rawStringDecoder
if (self.options.rawStringDecoder) {
self.registRawStringDecoder(self.options.rawStringDecoder);
}
// re-calculate elFinder node z-index
self.zIndexCalc();
self.load().debug('api', self.api);
// update ui's size after init
node.trigger('resize');
// initial open
open(data);
self.trigger('open', data, false);
self.trigger('opendone');
if (inFrame && self.options.enableAlways) {
$(window).trigger('focus');
}
// check self.trashes
$.each(self.trashes, function(th) {
var dir = self.file(th),
src;
if (! dir) {
toChkTh[th] = true;
} else if (dir.mime !== 'directory' || ! dir.write) {
trashDisable(th);
}
});
if (Object.keys(toChkTh).length) {
self.request({
data : {cmd : 'info', targets : Object.keys(toChkTh)},
preventDefault : true
}).done(function(data) {
if (data && data.files) {
$.each(data.files, function(i, dir) {
if (dir.mime === 'directory' && dir.write) {
delete toChkTh[dir.hash];
}
});
}
}).always(function() {
$.each(toChkTh, trashDisable);
});
}
// to enable / disable
self[self.options.enableAlways? 'enable' : 'disable']();
});
// self.timeEnd('load');
// End of bootUp()
};
// call bootCallback function with elFinder instance, extraObject - { dfrdsBeforeBootup: dfrdsBeforeBootup }
if (bootCallback && typeof bootCallback === 'function') {
self.bootCallback = bootCallback;
bootCallback.call(node.get(0), self, { dfrdsBeforeBootup: dfrdsBeforeBootup });
}
// call dfrdsBeforeBootup functions then boot up elFinder
$.when.apply(null, dfrdsBeforeBootup).done(function() {
bootUp();
}).fail(function(error) {
self.error(error);
});
};
//register elFinder to global scope
if (typeof toGlobal === 'undefined' || toGlobal) {
window.elFinder = elFinder;
}
/**
* Prototype
*
* @type Object
*/
elFinder.prototype = {
uniqueid : 0,
res : function(type, id) {
return this.resources[type] && this.resources[type][id];
},
/**
* User os. Required to bind native shortcuts for open/rename
*
* @type String
**/
OS : navigator.userAgent.indexOf('Mac') !== -1 ? 'mac' : navigator.userAgent.indexOf('Win') !== -1 ? 'win' : 'other',
/**
* User browser UA.
* jQuery.browser: version deprecated: 1.3, removed: 1.9
*
* @type Object
**/
UA : (function(){
var self = this,
webkit = !document.unqueID && !window.opera && !window.sidebar && window.localStorage && 'WebkitAppearance' in document.documentElement.style,
chrome = webkit && window.chrome,
/*setRotated = function() {
var a = ((screen && screen.orientation && screen.orientation.angle) || window.orientation || 0) + 0;
if (a === -90) {
a = 270;
}
UA.Angle = a;
UA.Rotated = a % 180 === 0? false : true;
},*/
UA = {
// Browser IE <= IE 6
ltIE6 : typeof window.addEventListener == "undefined" && typeof document.documentElement.style.maxHeight == "undefined",
// Browser IE <= IE 7
ltIE7 : typeof window.addEventListener == "undefined" && typeof document.querySelectorAll == "undefined",
// Browser IE <= IE 8
ltIE8 : typeof window.addEventListener == "undefined" && typeof document.getElementsByClassName == "undefined",
// Browser IE <= IE 9
ltIE9 : document.uniqueID && document.documentMode <= 9,
// Browser IE <= IE 10
ltIE10 : document.uniqueID && document.documentMode <= 10,
// Browser IE >= IE 11
gtIE11 : document.uniqueID && document.documentMode >= 11,
IE : document.uniqueID,
Firefox : window.sidebar,
Opera : window.opera,
Webkit : webkit,
Chrome : chrome,
Edge : (chrome && window.msCredentials)? true : false,
Safari : webkit && !window.chrome,
Mobile : typeof window.orientation != "undefined",
Touch : typeof window.ontouchstart != "undefined",
iOS : navigator.platform.match(/^iP(?:[ao]d|hone)/),
Fullscreen : (typeof (document.exitFullscreen || document.webkitExitFullscreen || document.mozCancelFullScreen || document.msExitFullscreen) !== 'undefined'),
Angle : 0,
Rotated : false,
CSS : (function() {
var aStyle = document.createElement('a').style,
pStyle = document.createElement('p').style,
css;
css = 'position:sticky;position:-webkit-sticky;';
css += 'width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:max-content;';
aStyle.cssText = css;
return {
positionSticky : aStyle.position.indexOf('sticky')!==-1,
widthMaxContent : aStyle.width.indexOf('max-content')!==-1,
flex : typeof pStyle.flex !== 'undefined'
};
})()
};
return UA;
})(),
/**
* Has RequireJS?
*
* @type Boolean
*/
hasRequire : (typeof define === 'function' && define.amd),
/**
* Current request command
*
* @type String
*/
currentReqCmd : '',
/**
* Current keyboard state
*
* @type Object
*/
keyState : {},
/**
* Internationalization object
*
* @type Object
*/
i18 : {
en : {
translator : '',
language : 'English',
direction : 'ltr',
dateFormat : 'd.m.Y H:i',
fancyDateFormat : '$1 H:i',
nonameDateFormat : 'ymd-His',
messages : {}
},
months : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
monthsShort : ['msJan', 'msFeb', 'msMar', 'msApr', 'msMay', 'msJun', 'msJul', 'msAug', 'msSep', 'msOct', 'msNov', 'msDec'],
days : ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
daysShort : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
},
/**
* File mimetype to kind mapping
*
* @type Object
*/
kinds : {
'unknown' : 'Unknown',
'directory' : 'Folder',
'group' : 'Selects',
'symlink' : 'Alias',
'symlink-broken' : 'AliasBroken',
'application/x-empty' : 'TextPlain',
'application/postscript' : 'Postscript',
'application/vnd.ms-office' : 'MsOffice',
'application/msword' : 'MsWord',
'application/vnd.ms-word' : 'MsWord',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document' : 'MsWord',
'application/vnd.ms-word.document.macroEnabled.12' : 'MsWord',
'application/vnd.openxmlformats-officedocument.wordprocessingml.template' : 'MsWord',
'application/vnd.ms-word.template.macroEnabled.12' : 'MsWord',
'application/vnd.ms-excel' : 'MsExcel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' : 'MsExcel',
'application/vnd.ms-excel.sheet.macroEnabled.12' : 'MsExcel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.template' : 'MsExcel',
'application/vnd.ms-excel.template.macroEnabled.12' : 'MsExcel',
'application/vnd.ms-excel.sheet.binary.macroEnabled.12' : 'MsExcel',
'application/vnd.ms-excel.addin.macroEnabled.12' : 'MsExcel',
'application/vnd.ms-powerpoint' : 'MsPP',
'application/vnd.openxmlformats-officedocument.presentationml.presentation' : 'MsPP',
'application/vnd.ms-powerpoint.presentation.macroEnabled.12' : 'MsPP',
'application/vnd.openxmlformats-officedocument.presentationml.slideshow' : 'MsPP',
'application/vnd.ms-powerpoint.slideshow.macroEnabled.12' : 'MsPP',
'application/vnd.openxmlformats-officedocument.presentationml.template' : 'MsPP',
'application/vnd.ms-powerpoint.template.macroEnabled.12' : 'MsPP',
'application/vnd.ms-powerpoint.addin.macroEnabled.12' : 'MsPP',
'application/vnd.openxmlformats-officedocument.presentationml.slide' : 'MsPP',
'application/vnd.ms-powerpoint.slide.macroEnabled.12' : 'MsPP',
'application/pdf' : 'PDF',
'application/xml' : 'XML',
'application/vnd.oasis.opendocument.text' : 'OO',
'application/vnd.oasis.opendocument.text-template' : 'OO',
'application/vnd.oasis.opendocument.text-web' : 'OO',
'application/vnd.oasis.opendocument.text-master' : 'OO',
'application/vnd.oasis.opendocument.graphics' : 'OO',
'application/vnd.oasis.opendocument.graphics-template' : 'OO',
'application/vnd.oasis.opendocument.presentation' : 'OO',
'application/vnd.oasis.opendocument.presentation-template' : 'OO',
'application/vnd.oasis.opendocument.spreadsheet' : 'OO',
'application/vnd.oasis.opendocument.spreadsheet-template' : 'OO',
'application/vnd.oasis.opendocument.chart' : 'OO',
'application/vnd.oasis.opendocument.formula' : 'OO',
'application/vnd.oasis.opendocument.database' : 'OO',
'application/vnd.oasis.opendocument.image' : 'OO',
'application/vnd.openofficeorg.extension' : 'OO',
'application/x-shockwave-flash' : 'AppFlash',
'application/flash-video' : 'Flash video',
'application/x-bittorrent' : 'Torrent',
'application/javascript' : 'JS',
'application/rtf' : 'RTF',
'application/rtfd' : 'RTF',
'application/x-font-ttf' : 'TTF',
'application/x-font-otf' : 'OTF',
'application/x-rpm' : 'RPM',
'application/x-web-config' : 'TextPlain',
'application/xhtml+xml' : 'HTML',
'application/docbook+xml' : 'DOCBOOK',
'application/x-awk' : 'AWK',
'application/x-gzip' : 'GZIP',
'application/x-bzip2' : 'BZIP',
'application/x-xz' : 'XZ',
'application/zip' : 'ZIP',
'application/x-zip' : 'ZIP',
'application/x-rar' : 'RAR',
'application/x-tar' : 'TAR',
'application/x-7z-compressed' : '7z',
'application/x-jar' : 'JAR',
'text/plain' : 'TextPlain',
'text/x-php' : 'PHP',
'text/html' : 'HTML',
'text/javascript' : 'JS',
'text/css' : 'CSS',
'text/rtf' : 'RTF',
'text/rtfd' : 'RTF',
'text/x-c' : 'C',
'text/x-csrc' : 'C',
'text/x-chdr' : 'CHeader',
'text/x-c++' : 'CPP',
'text/x-c++src' : 'CPP',
'text/x-c++hdr' : 'CPPHeader',
'text/x-shellscript' : 'Shell',
'application/x-csh' : 'Shell',
'text/x-python' : 'Python',
'text/x-java' : 'Java',
'text/x-java-source' : 'Java',
'text/x-ruby' : 'Ruby',
'text/x-perl' : 'Perl',
'text/x-sql' : 'SQL',
'text/xml' : 'XML',
'text/x-comma-separated-values' : 'CSV',
'text/x-markdown' : 'Markdown',
'image/x-ms-bmp' : 'BMP',
'image/jpeg' : 'JPEG',
'image/gif' : 'GIF',
'image/png' : 'PNG',
'image/tiff' : 'TIFF',
'image/x-targa' : 'TGA',
'image/vnd.adobe.photoshop' : 'PSD',
'image/xbm' : 'XBITMAP',
'image/pxm' : 'PXM',
'audio/mpeg' : 'AudioMPEG',
'audio/midi' : 'AudioMIDI',
'audio/ogg' : 'AudioOGG',
'audio/mp4' : 'AudioMPEG4',
'audio/x-m4a' : 'AudioMPEG4',
'audio/wav' : 'AudioWAV',
'audio/x-mp3-playlist' : 'AudioPlaylist',
'video/x-dv' : 'VideoDV',
'video/mp4' : 'VideoMPEG4',
'video/mpeg' : 'VideoMPEG',
'video/x-msvideo' : 'VideoAVI',
'video/quicktime' : 'VideoMOV',
'video/x-ms-wmv' : 'VideoWM',
'video/x-flv' : 'VideoFlash',
'video/x-matroska' : 'VideoMKV',
'video/ogg' : 'VideoOGG'
},
/**
* File mimetype to file extention mapping
*
* @type Object
* @see elFinder.mimetypes.js
*/
mimeTypes : {},
/**
* Ajax request data validation rules
*
* @type Object
*/
rules : {
defaults : function(data) {
if (!data
|| (data.added && !Array.isArray(data.added))
|| (data.removed && !Array.isArray(data.removed))
|| (data.changed && !Array.isArray(data.changed))) {
return false;
}
return true;
},
open : function(data) { return data && data.cwd && data.files && $.isPlainObject(data.cwd) && Array.isArray(data.files); },
tree : function(data) { return data && data.tree && Array.isArray(data.tree); },
parents : function(data) { return data && data.tree && Array.isArray(data.tree); },
tmb : function(data) { return data && data.images && ($.isPlainObject(data.images) || Array.isArray(data.images)); },
upload : function(data) { return data && ($.isPlainObject(data.added) || Array.isArray(data.added));},
search : function(data) { return data && data.files && Array.isArray(data.files); }
},
/**
* Commands costructors
*
* @type Object
*/
commands : {},
/**
* Commands to add the item (space delimited)
*
* @type String
*/
cmdsToAdd : 'archive duplicate extract mkdir mkfile paste rm upload',
parseUploadData : function(text) {
var self = this,
data;
if (!$.trim(text)) {
return {error : ['errResponse', 'errDataEmpty']};
}
try {
data = JSON.parse(text);
} catch (e) {
return {error : ['errResponse', 'errDataNotJSON']};
}
data = self.normalize(data);
if (!self.validResponse('upload', data)) {
return {error : (response.norError || ['errResponse'])};
}
data.removed = $.merge((data.removed || []), $.map(data.added || [], function(f) { return self.file(f.hash)? f.hash : null; }));
return data;
},
iframeCnt : 0,
uploads : {
// xhr muiti uploading flag
xhrUploading: false,
// Timer of request fail to sync
failSyncTm: null,
// current chunkfail requesting chunk
chunkfailReq: {},
// check file/dir exists
checkExists: function(files, target, fm, isDir) {
var dfrd = $.Deferred(),
names, renames = [], hashes = {}, chkFiles = [],
cancel = function() {
var i = files.length;
while (--i > -1) {
files[i]._remove = true;
}
},
resolve = function() {
dfrd.resolve(renames, hashes);
},
check = function() {
var existed = [], exists = [], i, c,
pathStr = target !== fm.cwd().hash? fm.path(target, true) + fm.option('separator', target) : '',
confirm = function(ndx) {
var last = ndx == exists.length-1,
opts = {
cssClass : 'elfinder-confirm-upload',
title : fm.i18n('cmdupload'),
text : ['errExists', pathStr + exists[ndx].name, 'confirmRepl'],
all : !last,
accept : {
label : 'btnYes',
callback : function(all) {
!last && !all
? confirm(++ndx)
: resolve();
}
},
reject : {
label : 'btnNo',
callback : function(all) {
var i;
if (all) {
i = exists.length;
while (ndx < i--) {
files[exists[i].i]._remove = true;
}
} else {
files[exists[ndx].i]._remove = true;
}
!last && !all
? confirm(++ndx)
: resolve();
}
},
cancel : {
label : 'btnCancel',
callback : function() {
cancel();
resolve();
}
},
buttons : [
{
label : 'btnBackup',
cssClass : 'elfinder-confirm-btn-backup',
callback : function(all) {
var i;
if (all) {
i = exists.length;
while (ndx < i--) {
renames.push(exists[i].name);
}
} else {
renames.push(exists[ndx].name);
}
!last && !all
? confirm(++ndx)
: resolve();
}
}
]
};
if (!isDir) {
opts.buttons.push({
label : 'btnRename' + (last? '' : 'All'),
cssClass : 'elfinder-confirm-btn-rename',
callback : function() {
renames = null;
resolve();
}
});
}
if (fm.iframeCnt > 0) {
delete opts.reject;
}
fm.confirm(opts);
};
if (! fm.file(target).read) {
// for dropbox type
resolve();
return;
}
names = $.map(files, function(file, i) { return file.name && (!fm.UA.iOS || file.name !== 'image.jpg')? {i: i, name: file.name} : null ;});
fm.request({
data : {cmd : 'ls', target : target, intersect : $.map(names, function(item) { return item.name;})},
notify : {type : 'preupload', cnt : 1, hideCnt : true},
preventDefault : true
})
.done(function(data) {
var existedArr, cwdItems;
if (data) {
if (data.error) {
cancel();
} else {
if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
if (data.list) {
if (Array.isArray(data.list)) {
existed = data.list || [];
} else {
existedArr = [];
existed = $.map(data.list, 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);
}
hashes = data.list;
}
exists = $.grep(names, function(name){
return $.inArray(name.name, existed) !== -1 ? true : false ;
});
if (exists.length && existed.length && target == fm.cwd().hash) {
cwdItems = $.map(fm.files(target), function(file) { return file.name; } );
if ($.grep(existed, function(n) {
return $.inArray(n, cwdItems) === -1? true : false;
}).length){
fm.sync();
}
}
}
}
}
}
if (exists.length > 0) {
confirm(0);
} else {
resolve();
}
})
.fail(function(error) {
cancel();
resolve();
error && fm.error(error);
});
};
if (fm.api >= 2.1 && typeof files[0] == 'object') {
check();
} else {
resolve();
}
return dfrd;
},
// check droped contents
checkFile : function(data, fm, target) {
if (!!data.checked || data.type == 'files') {
return data.files;
} else if (data.type == 'data') {
var dfrd = $.Deferred(),
scanDfd = $.Deferred(),
files = [],
paths = [],
dirctorys = [],
processing = 0,
items,
mkdirs = [],
cancel = false,
toArray = function(list) {
return Array.prototype.slice.call(list || [], 0);
},
doScan = function(items) {
var entry, readEntries,
excludes = fm.options.folderUploadExclude[fm.OS] || null,
length = items.length,
check = function() {
if (--processing < 1 && scanDfd.state() === 'pending') {
scanDfd.resolve();
}
},
pushItem = function(file) {
if (! excludes || ! file.name.match(excludes)) {
paths.push(entry.fullPath || '');
files.push(file);
}
check();
},
readEntries = function(dirReader) {
var entries = [],
read = function() {
dirReader.readEntries(function(results) {
if (cancel || !results.length) {
for (var i = 0; i < entries.length; i++) {
if (cancel) {
scanDfd.reject();
break;
}
doScan([entries[i]]);
}
check();
} else {
entries = entries.concat(toArray(results));
read();
}
}, check);
};
read();
};
processing++;
for (var i = 0; i < length; i++) {
if (cancel) {
scanDfd.reject();
break;
}
entry = items[i];
if (entry) {
if (entry.isFile) {
processing++;
entry.file(pushItem, check);
} else if (entry.isDirectory) {
if (fm.api >= 2.1) {
processing++;
mkdirs.push(entry.fullPath);
readEntries(entry.createReader()); // Start reading dirs.
}
}
}
}
check();
return scanDfd;
}, hasDirs;
items = $.map(data.files.items, function(item){
return item.getAsEntry? item.getAsEntry() : item.webkitGetAsEntry();
});
$.each(items, function(i, item) {
if (item.isDirectory) {
hasDirs = true;
return false;
}
});
if (items.length > 0) {
fm.uploads.checkExists(items, target, fm, hasDirs).done(function(renames, hashes){
var dfds = [];
if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
if (renames === null) {
data.overwrite = 0;
renames = [];
}
items = $.grep(items, function(item){
var i, bak, hash, dfd, hi;
if (item.isDirectory && renames.length) {
i = $.inArray(item.name, renames);
if (i !== -1) {
renames.splice(i, 1);
bak = fm.uniqueName(item.name + fm.options.backupSuffix , null, '');
$.each(hashes, function(h, name) {
if (item.name == name) {
hash = h;
return false;
}
});
if (! hash) {
hash = fm.fileByName(item.name, target).hash;
}
fm.lockfiles({files : [hash]});
dfd = fm.request({
data : {cmd : 'rename', target : hash, name : bak},
notify : {type : 'rename', cnt : 1}
})
.fail(function() {
item._remove = true;
fm.sync();
})
.always(function() {
fm.unlockfiles({files : [hash]});
});
dfds.push(dfd);
}
}
return !item._remove? true : false;
});
}
$.when.apply($, dfds).done(function(){
var notifyto, msg,
id = +new Date();
if (items.length > 0) {
msg = fm.escape(items[0].name);
if (items.length > 1) {
msg += ' ... ' + items.length + fm.i18n('items');
}
notifyto = setTimeout(function() {
fm.notify({
type : 'readdir',
id : id,
cnt : 1,
hideCnt: true,
msg : fm.i18n('ntfreaddir') + ' (' + msg + ')',
cancel: function() {
cancel = true;
}
});
}, fm.options.notifyDelay);
doScan(items).done(function() {
notifyto && clearTimeout(notifyto);
fm.notify({type : 'readdir', id: id, cnt : -1});
if (cancel) {
dfrd.reject();
} else {
dfrd.resolve([files, paths, renames, hashes, mkdirs]);
}
}).fail(function() {
dfrd.reject();
});
} else {
dfrd.reject();
}
});
});
return dfrd.promise();
} else {
return dfrd.reject();
}
} else {
var ret = [];
var check = [];
var str = data.files[0];
if (data.type == 'html') {
var tmp = $("<html/>").append($.parseHTML(str.replace(/ src=/ig, ' _elfsrc='))),
atag;
$('img[_elfsrc]', tmp).each(function(){
var url, purl,
self = $(this),
pa = self.closest('a');
if (pa && pa.attr('href') && pa.attr('href').match(/\.(?:jpe?g|gif|bmp|png)/i)) {
purl = pa.attr('href');
}
url = self.attr('_elfsrc');
if (url) {
if (purl) {
$.inArray(purl, ret) == -1 && ret.push(purl);
$.inArray(url, check) == -1 && check.push(url);
} else {
$.inArray(url, ret) == -1 && ret.push(url);
}
}
// Probably it's clipboard data
if (ret.length === 1 && ret[0].match(/^data:image\/png/)) {
data.clipdata = true;
}
});
atag = $('a[href]', tmp);
atag.each(function(){
var text, loc,
parseUrl = function(url) {
var a = document.createElement('a');
a.href = url;
return a;
};
if (text = $(this).text()) {
loc = parseUrl($(this).attr('href'));
if (loc.href && loc.href.match(/^(?:ht|f)tp/i) && (atag.length === 1 || ! loc.pathname.match(/(?:\.html?|\/[^\/.]*)$/i) || $.trim(text).match(/\.[a-z0-9-]{1,10}$/i))) {
if ($.inArray(loc.href, ret) == -1 && $.inArray(loc.href, check) == -1) ret.push(loc.href);
}
}
});
} else {
var regex, m, url;
regex = /(http[^<>"{}|\\^\[\]`\s]+)/ig;
while (m = regex.exec(str)) {
url = m[1].replace(/&amp;/g, '&');
if ($.inArray(url, ret) == -1) ret.push(url);
}
}
return ret;
}
},
// upload transport using XMLHttpRequest
xhr : function(data, fm) {
var self = fm ? fm : this,
node = self.getUI(),
xhr = new XMLHttpRequest(),
notifyto = null, notifyto2 = null,
dataChecked = data.checked,
isDataType = (data.isDataType || data.type == 'data'),
target = (data.target || self.cwd().hash),
dropEvt = (data.dropEvt || null),
extraData  = data.extraData || null,
chunkEnable = (self.option('uploadMaxConn', target) != -1),
multiMax = Math.min(5, Math.max(1, self.option('uploadMaxConn', target))),
retryWait = 10000, // 10 sec
retryMax = 30, // 10 sec * 30 = 300 secs (Max 5 mins)
retry = 0,
getFile = function(files) {
var dfd = $.Deferred(),
file;
if (files.promise) {
files.always(function(f) {
dfd.resolve(Array.isArray(f) && f.length? (isDataType? f[0][0] : f[0]) : {});
});
} else {
dfd.resolve(files.length? (isDataType? files[0][0] : files[0]) : {});
}
return dfd;
},
dfrd = $.Deferred()
.fail(function(err) {
var error = self.parseError(err),
userAbort;
if (error === 'userabort') {
userAbort = true;
error = void 0;
}
if (files && (self.uploads.xhrUploading || userAbort)) {
// send request om fail
getFile(files).done(function(file) {
if (! file._cid) {
// send sync request
self.uploads.failSyncTm && clearTimeout(self.uploads.failSyncTm);
self.uploads.failSyncTm = setTimeout(function() {
self.sync(target);
}, 1000);
} else if (! self.uploads.chunkfailReq[file._cid]) {
// send chunkfail request
self.uploads.chunkfailReq[file._cid] = true;
setTimeout(function() {
fm.request({
data : {
cmd: 'upload',
target: target,
chunk: file._chunk,
cid: file._cid,
upload: ['chunkfail'],
mimes: 'chunkfail'
},
options : {
type: 'post',
url: self.uploadURL
},
preventDefault: true
}).always(function() {
delete self.uploads.chunkfailReq[file._chunk];
});
}, 1000);
}
});
}
!userAbort && self.sync();
self.uploads.xhrUploading = false;
files = null;
error && self.error(error);
})
.done(function(data) {
self.uploads.xhrUploading = false;
files = null;
if (data) {
self.currentReqCmd = 'upload';
data.warning && self.error(data.warning);
self.updateCache(data);
data.removed && data.removed.length && self.remove(data);
data.added && data.added.length && self.add(data);
data.changed && data.changed.length && self.change(data);
self.trigger('upload', data, false);
self.trigger('uploaddone');
if (data.toasts && Array.isArray(data.toasts)) {
$.each(data.toasts, function() {
this.msg && self.toast(this);
});
}
data.sync && self.sync();
data.debug && fm.debug('backend-debug', data);
}
})
.always(function() {
self.abortXHR(xhr);
// unregist fnAbort function
node.off('uploadabort', fnAbort);
$(window).off('unload', fnAbort);
notifyto && clearTimeout(notifyto);
notifyto2 && clearTimeout(notifyto2);
dataChecked && !data.multiupload && checkNotify() && self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0});
chunkMerge && notifyElm.children('.elfinder-notify-chunkmerge').length && self.notify({type : 'chunkmerge', cnt : -1});
}),
formData = new FormData(),
files = data.input ? data.input.files : self.uploads.checkFile(data, self, target),
cnt = data.checked? (isDataType? files[0].length : files.length) : files.length,
loaded = 0,
prev = 0,
filesize = 0,
notify = false,
notifyElm = self.ui.notify,
cancelBtn = true,
abort = false,
checkNotify = function() {
if (!notify && (ntfUpload = notifyElm.children('.elfinder-notify-upload')).length) {
notify = true;
}
return notify;
},
fnAbort = function(e, error) {
abort = true;
self.abortXHR(xhr, { quiet: true, abort: true });
dfrd.reject(error);
if (checkNotify()) {
self.notify({type : 'upload', cnt : ntfUpload.data('cnt') * -1, progress : 0, size : 0});
}
},
cancelToggle = function(show) {
ntfUpload.children('.elfinder-notify-cancel')[show? 'show':'hide']();
},
startNotify = function(size) {
if (!size) size = filesize;
return setTimeout(function() {
notify = true;
self.notify({type : 'upload', cnt : cnt, progress : loaded - prev, size : size,
cancel: function() {
node.trigger('uploadabort', 'userabort');
}
});
ntfUpload = notifyElm.children('.elfinder-notify-upload');
prev = loaded;
if (data.multiupload) {
cancelBtn && cancelToggle(true);
} else {
cancelToggle(cancelBtn && loaded < size);
}
}, self.options.notifyDelay);
},
doRetry = function() {
if (retry++ <= retryMax) {
if (checkNotify() && prev) {
self.notify({type : 'upload', cnt : 0, progress : 0, size : prev});
}
self.abortXHR(xhr, { quiet: true });
prev = loaded = 0;
setTimeout(function() {
var reqId;
if (! abort) {
xhr.open('POST', self.uploadURL, true);
if (self.api >= 2.1029) {
reqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16);
(typeof formData['delete'] === 'function') && formData['delete']('reqid');
formData.append('reqid', reqId);
xhr._requestId = reqId;
}
xhr.send(formData);
}
}, retryWait);
} else {
node.trigger('uploadabort', ['errAbort', 'errTimeout']);
}
},
progress = function() {
var node;
if (notify) {
dfrd.notifyWith(ntfUpload, [{
cnt: ntfUpload.data('cnt'),
progress: ntfUpload.data('progress'),
total: ntfUpload.data('total')
}]);
}
},
renames = (data.renames || null),
hashes = (data.hashes || null),
chunkMerge = false,
ntfUpload = $();
// regist fnAbort function
node.one('uploadabort', fnAbort);
$(window).one('unload.' + fm.namespace, fnAbort);
!chunkMerge && (prev = loaded);
if (!isDataType && !cnt) {
return dfrd.reject(['errUploadNoFiles']);
}
xhr.addEventListener('error', function() {
if (xhr.status == 0) {
if (abort) {
dfrd.reject();
} else {
// ff bug while send zero sized file
// for safari - send directory
if (!isDataType && data.files && $.grep(data.files, function(f){return ! f.type && f.size === (self.UA.Safari? 1802 : 0)? true : false;}).length) {
errors.push('errFolderUpload');
dfrd.reject(['errAbort', 'errFolderUpload']);
} else if (data.input && $.grep(data.input.files, function(f){return ! f.type && f.size === (self.UA.Safari? 1802 : 0)? true : false;}).length) {
dfrd.reject(['errUploadNoFiles']);
} else {
doRetry();
}
}
} else {
node.trigger('uploadabort', 'errConnect');
}
}, false);
xhr.addEventListener('load', function(e) {
var status = xhr.status, res, curr = 0, error = '', errData, errObj;
if (status >= 400) {
if (status > 500) {
error = 'errResponse';
} else {
error = ['errResponse', 'errServerError'];
}
} else {
if (!xhr.responseText) {
error = ['errResponse', 'errDataEmpty'];
}
}
if (error) {
node.trigger('uploadabort');
getFile(files).done(function(file) {
return dfrd.reject(file._cid? null : error);
});
}
loaded = filesize;
if (checkNotify() && (curr = loaded - prev)) {
self.notify({type : 'upload', cnt : 0, progress : curr, size : 0});
progress();
}
res = self.parseUploadData(xhr.responseText);
// chunked upload commit
if (res._chunkmerged) {
formData = new FormData();
var _file = [{_chunkmerged: res._chunkmerged, _name: res._name, _mtime: res._mtime}];
chunkMerge = true;
node.off('uploadabort', fnAbort);
notifyto2 = setTimeout(function() {
self.notify({type : 'chunkmerge', cnt : 1});
}, self.options.notifyDelay);
isDataType? send(_file, files[1]) : send(_file);
return;
}
res._multiupload = data.multiupload? true : false;
if (res.error) {
errData = {
cmd: 'upload',
err: res,
xhr: xhr,
rc: xhr.status
};
self.trigger('uploadfail', res);
// trigger "requestError" event
self.trigger('requestError', errData);
if (errData._event && errData._event.isDefaultPrevented()) {
res.error = '';
}
if (res._chunkfailure || res._multiupload) {
abort = true;
self.uploads.xhrUploading = false;
notifyto && clearTimeout(notifyto);
if (ntfUpload.length) {
self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0});
dfrd.reject(res);
} else {
// for multi connection
dfrd.reject();
}
} else {
dfrd.reject(res);
}
} else {
dfrd.resolve(res);
}
}, false);
xhr.upload.addEventListener('loadstart', function(e) {
if (!chunkMerge && e.lengthComputable) {
loaded = e.loaded;
retry && (loaded = 0);
filesize = e.total;
if (!loaded) {
loaded = parseInt(filesize * 0.05);
}
if (checkNotify()) {
self.notify({type : 'upload', cnt : 0, progress : loaded - prev, size : data.multiupload? 0 : filesize});
prev = loaded;
progress();
}
}
}, false);
xhr.upload.addEventListener('progress', function(e) {
var curr;
if (e.lengthComputable && !chunkMerge && xhr.readyState < 2) {
loaded = e.loaded;
// to avoid strange bug in safari (not in chrome) with drag&drop.
// bug: macos finder opened in any folder,
// reset safari cache (option+command+e), reload elfinder page,
// drop file from finder
// on first attempt request starts (progress callback called ones) but never ends.
// any next drop - successfull.
if (!data.checked && loaded > 0 && !notifyto) {
notifyto = startNotify(xhr._totalSize - loaded);
}
if (!filesize) {
filesize = e.total;
if (!loaded) {
loaded = parseInt(filesize * 0.05);
}
}
curr = loaded - prev;
if (checkNotify() && (curr/e.total) >= 0.05) {
self.notify({type : 'upload', cnt : 0, progress : curr, size : 0});
prev = loaded;
progress();
}
if (! data.multiupload && loaded >= filesize) {
cancelBtn = false;
cancelToggle(false);
}
}
}, false);
var send = function(files, paths){
var size = 0,
fcnt = 1,
sfiles = [],
c = 0,
total = cnt,
maxFileSize,
totalSize = 0,
chunked = [],
chunkID = new Date().getTime().toString().substr(-9), // for take care of the 32bit backend system
BYTES_PER_CHUNK = Math.min((fm.uplMaxSize? fm.uplMaxSize : 2097152) - 8190, fm.options.uploadMaxChunkSize), // uplMaxSize margin 8kb or options.uploadMaxChunkSize
blobSlice = chunkEnable? false : '',
blobSize, blobMtime, i, start, end, chunks, blob, chunk, added, done, last, failChunk,
multi = function(files, num){
var sfiles = [], cid, sfilesLen = 0, cancelChk;
if (!abort) {
while(files.length && sfiles.length < num) {
sfiles.push(files.shift());
}
sfilesLen = sfiles.length;
if (sfilesLen) {
cancelChk = sfilesLen;
for (var i=0; i < sfilesLen; i++) {
if (abort) {
break;
}
cid = isDataType? (sfiles[i][0][0]._cid || null) : (sfiles[i][0]._cid || null);
if (!!failChunk[cid]) {
last--;
continue;
}
fm.exec('upload', {
type: data.type,
isDataType: isDataType,
files: sfiles[i],
checked: true,
target: target,
dropEvt: dropEvt,
renames: renames,
hashes: hashes,
multiupload: true,
overwrite: data.overwrite === 0? 0 : void 0
}, void 0, target)
.fail(function(error) {
if (error && error === 'No such command') {
abort = true;
fm.error(['errUpload', 'errPerm']);
}
if (cid) {
failChunk[cid] = true;
}
})
.always(function(e) {
if (e && e.added) added = $.merge(added, e.added);
if (last <= ++done) {
fm.trigger('multiupload', {added: added});
notifyto && clearTimeout(notifyto);
if (checkNotify()) {
self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0});
}
}
if (files.length) {
multi(files, 1); // Next one
} else {
if (--cancelChk <= 1) {
cancelBtn = false;
cancelToggle(false);
}
}
});
}
}
}
if (sfiles.length < 1 || abort) {
if (abort) {
notifyto && clearTimeout(notifyto);
if (cid) {
failChunk[cid] = true;
}
dfrd.reject();
} else {
dfrd.resolve();
self.uploads.xhrUploading = false;
}
}
},
check = function(){
if (!self.uploads.xhrUploading) {
self.uploads.xhrUploading = true;
multi(sfiles, multiMax); // Max connection: 3
} else {
setTimeout(check, 100);
}
},
reqId;
if (! dataChecked && (isDataType || data.type == 'files')) {
if (! (maxFileSize = fm.option('uploadMaxSize', target))) {
maxFileSize = 0;
}
for (i=0; i < files.length; i++) {
try {
blob = files[i];
blobSize = blob.size;
if (blobSlice === false) {
blobSlice = '';
if (self.api >= 2.1) {
if ('slice' in blob) {
blobSlice = 'slice';
} else if ('mozSlice' in blob) {
blobSlice = 'mozSlice';
} else if ('webkitSlice' in blob) {
blobSlice = 'webkitSlice';
}
}
}
} catch(e) {
cnt--;
total--;
continue;
}
// file size check
if ((maxFileSize && blobSize > maxFileSize) || (!blobSlice && fm.uplMaxSize && blobSize > fm.uplMaxSize)) {
self.error(['errUploadFile', blob.name, 'errUploadFileSize']);
cnt--;
total--;
continue;
}
// file mime check
if (blob.type && ! self.uploadMimeCheck(blob.type, target)) {
self.error(['errUploadFile', blob.name, 'errUploadMime', '(' + blob.type + ')']);
cnt--;
total--;
continue;
}
if (blobSlice && blobSize > BYTES_PER_CHUNK) {
start = 0;
end = BYTES_PER_CHUNK;
chunks = -1;
total = Math.floor((blobSize - 1) / BYTES_PER_CHUNK);
blobMtime = blob.lastModified? Math.round(blob.lastModified/1000) : 0;
totalSize += blobSize;
chunked[chunkID] = 0;
while(start < blobSize) {
chunk = blob[blobSlice](start, end);
chunk._chunk = blob.name + '.' + (++chunks) + '_' + total + '.part';
chunk._cid = chunkID;
chunk._range = start + ',' + chunk.size + ',' + blobSize;
chunk._mtime = blobMtime;
chunked[chunkID]++;
if (size) {
c++;
}
if (typeof sfiles[c] == 'undefined') {
sfiles[c] = [];
if (isDataType) {
sfiles[c][0] = [];
sfiles[c][1] = [];
}
}
size = BYTES_PER_CHUNK;
fcnt = 1;
if (isDataType) {
sfiles[c][0].push(chunk);
sfiles[c][1].push(paths[i]);
} else {
sfiles[c].push(chunk);
}
start = end;
end = start + BYTES_PER_CHUNK;
}
if (chunk == null) {
self.error(['errUploadFile', blob.name, 'errUploadFileSize']);
cnt--;
total--;
} else {
total += chunks;
size = 0;
fcnt = 1;
c++;
}
continue;
}
if ((fm.uplMaxSize && size + blobSize > fm.uplMaxSize) || fcnt > fm.uplMaxFile) {
size = 0;
fcnt = 1;
c++;
}
if (typeof sfiles[c] == 'undefined') {
sfiles[c] = [];
if (isDataType) {
sfiles[c][0] = [];
sfiles[c][1] = [];
}
}
if (isDataType) {
sfiles[c][0].push(blob);
sfiles[c][1].push(paths[i]);
} else {
sfiles[c].push(blob);
}
size += blobSize;
totalSize += blobSize;
fcnt++;
}
if (sfiles.length == 0) {
// no data
data.checked = true;
return false;
}
if (sfiles.length > 1) {
// multi upload
notifyto = startNotify(totalSize);
added = [];
done = 0;
last = sfiles.length;
failChunk = [];
check();
return true;
}
// single upload
if (isDataType) {
files = sfiles[0][0];
paths = sfiles[0][1];
} else {
files = sfiles[0];
}
}
if (!dataChecked) {
if (!fm.UA.Safari || !data.files) {
notifyto = startNotify(totalSize);
} else {
xhr._totalSize = totalSize;
}
}
dataChecked = true;
if (! files.length) {
dfrd.reject(['errUploadNoFiles']);
}
xhr.open('POST', self.uploadURL, true);
// set request headers
if (fm.customHeaders) {
$.each(fm.customHeaders, function(key) {
xhr.setRequestHeader(key, this);
});
}
// set xhrFields
if (fm.xhrFields) {
$.each(fm.xhrFields, function(key) {
if (key in xhr) {
xhr[key] = this;
}
});
}
if (self.api >= 2.1029) {
// request ID
reqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16);
formData.append('reqid', reqId);
xhr._requestId = reqId;
}
formData.append('cmd', 'upload');
formData.append(self.newAPI ? 'target' : 'current', target);
if (renames && renames.length) {
$.each(renames, function(i, v) {
formData.append('renames[]', v);
});
formData.append('suffix', fm.options.backupSuffix);
}
if (hashes) {
$.each(hashes, function(i, v) {
formData.append('hashes['+ i +']', v);
});
}
$.each(self.customData, function(key, val) {
formData.append(key, val);
});
$.each(self.options.onlyMimes, function(i, mime) {
formData.append('mimes[]', mime);
});
$.each(files, function(i, file) {
if (file._chunkmerged) {
formData.append('chunk', file._chunkmerged);
formData.append('upload[]', file._name);
formData.append('mtime[]', file._mtime);
} else {
if (file._chunkfail) {
formData.append('upload[]', 'chunkfail');
formData.append('mimes', 'chunkfail');
} else {
formData.append('upload[]', file);
if (data.clipdata) {
data.overwrite = 0;
formData.append('name[]', fm.date(fm.nonameDateFormat) + '.png');
}
if (file.name && fm.UA.iOS) {
if (file.name.match(/^image\.jpe?g$/i)) {
data.overwrite = 0;
formData.append('name[]', fm.date(fm.nonameDateFormat) + '.jpg');
} else if (file.name.match(/^capturedvideo\.mov$/i)) {
data.overwrite = 0;
formData.append('name[]', fm.date(fm.nonameDateFormat) + '.mov');
}
}
}
if (file._chunk) {
formData.append('chunk', file._chunk);
formData.append('cid' , file._cid);
formData.append('range', file._range);
formData.append('mtime[]', file._mtime);
} else {
formData.append('mtime[]', file.lastModified? Math.round(file.lastModified/1000) : 0);
}
}
});
if (isDataType) {
$.each(paths, function(i, path) {
formData.append('upload_path[]', path);
});
}
if (data.overwrite === 0) {
formData.append('overwrite', 0);
}
// send int value that which meta key was pressed when dropped as `dropWith`
if (dropEvt) {
formData.append('dropWith', parseInt(
(dropEvt.altKey ? '1' : '0')+
(dropEvt.ctrlKey ? '1' : '0')+
(dropEvt.metaKey ? '1' : '0')+
(dropEvt.shiftKey? '1' : '0'), 2));
}
// set extraData on current request
if (extraData) {
$.each(extraData, function(key, val) {
formData.append(key, val);
});
}
xhr.send(formData);
return true;
};
if (! isDataType) {
if (files.length > 0) {
if (! data.clipdata && renames == null) {
var mkdirs = [],
paths = [],
excludes = fm.options.folderUploadExclude[fm.OS] || null;
$.each(files, function(i, file) {
var relPath = file.webkitRelativePath || file.relativePath || '',
idx, rootDir;
if (! relPath) {
return false;
}
if (excludes && file.name.match(excludes)) {
file._remove = true;
relPath = void(0);
} else {
// add '/' as prefix to make same to folder uploading with DnD, see #2607
relPath = '/' + relPath.replace(/\/[^\/]*$/, '').replace(/^\//, '');
if (relPath && $.inArray(relPath, mkdirs) === -1) {
mkdirs.push(relPath);
// checking the root directory to supports <input type="file" webkitdirectory> see #2378
idx = relPath.substr(1).indexOf('/');
if (idx !== -1 && (rootDir = relPath.substr(0, idx + 1)) && $.inArray(rootDir, mkdirs) === -1) {
mkdirs.unshift(rootDir);
}
}
}
paths.push(relPath);
});
renames = [];
hashes = {};
if (mkdirs.length) {
(function() {
var checkDirs = $.map(mkdirs, function(name) { return name.substr(1).indexOf('/') === -1 ? {name: name.substr(1)} : null;}),
cancelDirs = [];
fm.uploads.checkExists(checkDirs, target, fm, true).done(
function(res, res2) {
var dfds = [], dfd, bak, hash;
if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
cancelDirs = $.map(checkDirs, function(dir) { return dir._remove? dir.name : null ;} );
checkDirs = $.grep(checkDirs, function(dir) { return !dir._remove? true : false ;} );
}
if (cancelDirs.length) {
$.each(paths.concat(), function(i, path) {
if ($.inArray(path, cancelDirs) === 0) {
files[i]._remove = true;
paths[i] = void(0);
}
});
}
files = $.grep(files, function(file) { return file._remove? false : true; });
paths = $.grep(paths, function(path) { return path === void 0 ? false : true; });
if (checkDirs.length) {
dfd = $.Deferred();
if (res.length) {
$.each(res, function(i, existName) {
// backup
bak = fm.uniqueName(existName + fm.options.backupSuffix , null, '');
$.each(res2, function(h, name) {
if (res[0] == name) {
hash = h;
return false;
}
});
if (! hash) {
hash = fm.fileByName(res[0], target).hash;
}
fm.lockfiles({files : [hash]});
dfds.push(
fm.request({
data : {cmd : 'rename', target : hash, name : bak},
notify : {type : 'rename', cnt : 1}
})
.fail(function(error) {
dfrd.reject(error);
fm.sync();
})
.always(function() {
fm.unlockfiles({files : [hash]});
})
);
});
} else {
dfds.push(null);
}
$.when.apply($, dfds).done(function() {
// ensure directories
fm.request({
data : {cmd : 'mkdir', target : target, dirs : mkdirs},
notify : {type : 'mkdir', cnt : mkdirs.length},
preventFail: true
})
.fail(function(error) {
error = error || ['errUnknown'];
if (error[0] === 'errCmdParams') {
multiMax = 1;
} else {
multiMax = 0;
dfrd.reject(error);
}
})
.done(function(data) {
var rm = false;
if (!data.hashes) {
data.hashes = {};
}
paths = $.map(paths.concat(), function(p, i) {
if (p === '/') {
return target;
} else {
if (data.hashes[p]) {
return data.hashes[p];
} else {
rm = true;
files[i]._remove = true;
return null;
}
}
});
if (rm) {
files = $.grep(files, function(file) { return file._remove? false : true; });
}
})
.always(function(data) {
if (multiMax) {
isDataType = true;
if (! send(files, paths)) {
dfrd.reject();
}
}
});
});
} else {
dfrd.reject();
}
}
);
})();
} else {
fm.uploads.checkExists(files, target, fm).done(
function(res, res2){
if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
hashes = res2;
if (res === null) {
data.overwrite = 0;
} else {
renames = res;
}
files = $.grep(files, function(file){return !file._remove? true : false ;});
}
cnt = files.length;
if (cnt > 0) {
if (! send(files)) {
dfrd.reject();
}
} else {
dfrd.reject();
}
}
);
}
} else {
if (! send(files)) {
dfrd.reject();
}
}
} else {
dfrd.reject();
}
} else {
if (dataChecked) {
send(files[0], files[1]);
} else {
files.done(function(result) { // result: [files, paths, renames, hashes, mkdirs]
renames = [];
cnt = result[0].length;
if (cnt) {
if (result[4] && result[4].length) {
// ensure directories
fm.request({
data : {cmd : 'mkdir', target : target, dirs : result[4]},
notify : {type : 'mkdir', cnt : result[4].length},
preventFail: true
})
.fail(function(error) {
error = error || ['errUnknown'];
if (error[0] === 'errCmdParams') {
multiMax = 1;
} else {
multiMax = 0;
dfrd.reject(error);
}
})
.done(function(data) {
var rm = false;
if (!data.hashes) {
data.hashes = {};
}
result[1] = $.map(result[1], function(p, i) {
p = p.replace(/\/[^\/]*$/, '');
if (p === '') {
return target;
} else {
if (data.hashes[p]) {
return data.hashes[p];
} else {
rm = true;
result[0][i]._remove = true;
return null;
}
}
});
if (rm) {
result[0] = $.grep(result[0], function(file) { return file._remove? false : true; });
}
})
.always(function(data) {
if (multiMax) {
renames = result[2];
hashes = result[3];
send(result[0], result[1]);
}
});
return;
} else {
result[1] = $.map(result[1], function() { return target; });
}
renames = result[2];
hashes = result[3];
send(result[0], result[1]);
} else {
dfrd.reject(['errUploadNoFiles']);
}
}).fail(function(){
dfrd.reject();
});
}
}
return dfrd;
},
// upload transport using iframe
iframe : function(data, fm) {
var self = fm ? fm : this,
input = data.input? data.input : false,
files = !input ? self.uploads.checkFile(data, self) : false,
dfrd = $.Deferred()
.fail(function(error) {
error && self.error(error);
}),
name = 'iframe-'+fm.namespace+(++self.iframeCnt),
form = $('<form action="'+self.uploadURL+'" method="post" enctype="multipart/form-data" encoding="multipart/form-data" target="'+name+'" style="display:none"><input type="hidden" name="cmd" value="upload" /></form>'),
msie = this.UA.IE,
// clear timeouts, close notification dialog, remove form/iframe
onload = function() {
abortto && clearTimeout(abortto);
notifyto && clearTimeout(notifyto);
notify && self.notify({type : 'upload', cnt : -cnt});
setTimeout(function() {
msie && $('<iframe src="javascript:false;"/>').appendTo(form);
form.remove();
iframe.remove();
}, 100);
},
iframe = $('<iframe src="'+(msie ? 'javascript:false;' : 'about:blank')+'" name="'+name+'" style="position:absolute;left:-1000px;top:-1000px" />')
.on('load', function() {
iframe.off('load')
.on('load', function() {
onload();
// data will be processed in callback response or window onmessage
dfrd.resolve();
});
// notify dialog
notifyto = setTimeout(function() {
notify = true;
self.notify({type : 'upload', cnt : cnt});
}, self.options.notifyDelay);
// emulate abort on timeout
if (self.options.iframeTimeout > 0) {
abortto = setTimeout(function() {
onload();
dfrd.reject([errors.connect, errors.timeout]);
}, self.options.iframeTimeout);
}
form.submit();
}),
target = (data.target || self.cwd().hash),
names = [],
dfds = [],
renames = [],
hashes = {},
cnt, notify, notifyto, abortto;
if (files && files.length) {
$.each(files, function(i, val) {
form.append('<input type="hidden" name="upload[]" value="'+val+'"/>');
});
cnt = 1;
} else if (input && $(input).is(':file') && $(input).val()) {
if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
names = input.files? input.files : [{ name: $(input).val().replace(/^(?:.+[\\\/])?([^\\\/]+)$/, '$1') }];
//names = $.map(names, function(file){return file.name? { name: file.name } : null ;});
dfds.push(self.uploads.checkExists(names, target, self).done(
function(res, res2){
hashes = res2;
if (res === null) {
data.overwrite = 0;
} else{
renames = res;
cnt = $.grep(names, function(file){return !file._remove? true : false ;}).length;
if (cnt != names.length) {
cnt = 0;
}
}
}
));
}
cnt = input.files ? input.files.length : 1;
form.append(input);
} else {
return dfrd.reject();
}
$.when.apply($, dfds).done(function() {
if (cnt < 1) {
return dfrd.reject();
}
form.append('<input type="hidden" name="'+(self.newAPI ? 'target' : 'current')+'" value="'+target+'"/>')
.append('<input type="hidden" name="html" value="1"/>')
.append('<input type="hidden" name="node" value="'+self.id+'"/>')
.append($(input).attr('name', 'upload[]'));
if (renames.length > 0) {
$.each(renames, function(i, rename) {
form.append('<input type="hidden" name="renames[]" value="'+self.escape(rename)+'"/>');
});
form.append('<input type="hidden" name="suffix" value="'+fm.options.backupSuffix+'"/>');
}
if (hashes) {
$.each(renames, function(i, v) {
form.append('<input type="hidden" name="['+i+']" value="'+self.escape(v)+'"/>');
});
}
if (data.overwrite === 0) {
form.append('<input type="hidden" name="overwrite" value="0"/>');
}
$.each(self.options.onlyMimes||[], function(i, mime) {
form.append('<input type="hidden" name="mimes[]" value="'+self.escape(mime)+'"/>');
});
$.each(self.customData, function(key, val) {
form.append('<input type="hidden" name="'+key+'" value="'+self.escape(val)+'"/>');
});
form.appendTo('body');
iframe.appendTo('body');
});
return dfrd;
}
},
/**
* Bind callback to event(s) The callback is executed at most once per event.
* To bind to multiply events at once, separate events names by space
*
* @param String event name
* @param Function callback
* @param Boolan priority first
* @return elFinder
*/
one : function(ev, callback, priorityFirst) {
var self = this,
event = ev.toLowerCase(),
h = function(e, f) {
if (!self.toUnbindEvents[event]) {
self.toUnbindEvents[event] = [];
}
self.toUnbindEvents[event].push({
type: event,
callback: h
});
return (callback.done? callback.done : callback).apply(this, arguments);
};
if (callback.done) {
h = {done: h};
}
return this.bind(event, h, priorityFirst);
},
/**
* Set/get data into/from localStorage
*
* @param String key
* @param String|void value
* @return String|null
*/
localStorage : function(key, val) {
var self = this,
s = window.localStorage,
oldkey = 'elfinder-'+(key || '')+this.id, // old key of elFinder < 2.1.6
prefix = window.location.pathname+'-elfinder-',
suffix = this.id,
clrs = [],
retval, oldval, t, precnt, sufcnt;
// reset this node data
if (typeof(key) === 'undefined') {
precnt = prefix.length;
sufcnt = suffix.length * -1;
$.each(s, function(key) {
if (key.substr(0, precnt) === prefix && key.substr(sufcnt) === suffix) {
clrs.push(key);
}
});
$.each(clrs, function(i, key) {
s.removeItem(key);
});
return true;
}
// new key of elFinder >= 2.1.6
key = prefix+key+suffix;
if (val === null) {
return s.removeItem(key);
}
if (val === void(0) && !(retval = s.getItem(key)) && (oldval = s.getItem(oldkey))) {
val = oldval;
s.removeItem(oldkey);
}
if (val !== void(0)) {
t = typeof val;
if (t !== 'string' && t !== 'number') {
val = JSON.stringify(val);
}
try {
s.setItem(key, val);
} catch (e) {
try {
s.clear();
s.setItem(key, val);
} catch (e) {
self.debug('error', e.toString());
}
}
retval = s.getItem(key);
}
if (retval && (retval.substr(0,1) === '{' || retval.substr(0,1) === '[')) {
try {
return JSON.parse(retval);
} catch(e) {}
}
return retval;
},
/**
* Get/set cookie
*
* @param String cookie name
* @param String|void cookie value
* @return String|null
*/
cookie : function(name, value) {
var d, o, c, i, retval, t;
name = 'elfinder-'+name+this.id;
if (value === void(0)) {
if (document.cookie && document.cookie != '') {
c = document.cookie.split(';');
name += '=';
for (i=0; i<c.length; i++) {
c[i] = $.trim(c[i]);
if (c[i].substring(0, name.length) == name) {
retval = decodeURIComponent(c[i].substring(name.length));
if (retval.substr(0,1) === '{' || retval.substr(0,1) === '[') {
try {
return JSON.parse(retval);
} catch(e) {}
}
return retval;
}
}
}
return null;
}
o = Object.assign({}, this.options.cookie);
if (value === null) {
value = '';
o.expires = -1;
} else {
t = typeof value;
if (t !== 'string' && t !== 'number') {
value = JSON.stringify(value);
}
}
if (typeof(o.expires) == 'number') {
d = new Date();
d.setTime(d.getTime()+(o.expires * 86400000));
o.expires = d;
}
document.cookie = name+'='+encodeURIComponent(value)+'; expires='+o.expires.toUTCString()+(o.path ? '; path='+o.path : '')+(o.domain ? '; domain='+o.domain : '')+(o.secure ? '; secure' : '');
if (value && (value.substr(0,1) === '{' || value.substr(0,1) === '[')) {
try {
return JSON.parse(value);
} catch(e) {}
}
return value;
},
/**
* Get start directory (by location.hash or last opened directory)
*
* @return String
*/
startDir : function() {
var locHash = window.location.hash;
if (locHash && locHash.match(/^#elf_/)) {
return locHash.replace(/^#elf_/, '');
} else if (this.options.startPathHash) {
return this.options.startPathHash;
} else {
return this.lastDir();
}
},
/**
* Get/set last opened directory
*
* @param String|undefined dir hash
* @return String
*/
lastDir : function(hash) {
return this.options.rememberLastDir ? this.storage('lastdir', hash) : '';
},
/**
* Node for escape html entities in texts
*
* @type jQuery
*/
_node : $('<span/>'),
/**
* Replace not html-safe symbols to html entities
*
* @param String text to escape
* @return String
*/
escape : function(name) {
return this._node.text(name).html().replace(/"/g, '&quot;').replace(/'/g, '&#039;');
},
/**
* Cleanup ajax data.
* For old api convert data into new api format
*
* @param String command name
* @param Object data from backend
* @return Object
*/
normalize : function(data) {
var self = this,
fileFilter = (function() {
var func, filter;
if (filter = self.options.fileFilter) {
if (typeof filter === 'function') {
func = function(file) {
return filter.call(self, file);
};
} else if (filter instanceof RegExp) {
func = function(file) {
return filter.test(file.name);
};
}
}
return func? func : null;
})(),
chkCmdMap = function(opts) {
// Disable command to replace with other command
var disabled;
if (opts.uiCmdMap) {
if ($.isPlainObject(opts.uiCmdMap) && Object.keys(opts.uiCmdMap).length) {
if (!opts.disabledFlip) {
opts.disabledFlip = {};
}
disabled = opts.disabledFlip;
$.each(opts.uiCmdMap, function(f, t) {
if (t === 'hidden' && !disabled[f]) {
opts.disabled.push(f);
opts.disabledFlip[f] = true;
}
});
} else {
delete opts.uiCmdMap;
}
}
},
normalizeOptions = function(opts) {
var getType = function(v) {
var type = typeof v;
if (type === 'object' && Array.isArray(v)) {
type = 'array';
}
return type;
};
$.each(self.optionProperties, function(k, empty) {
if (empty !== void(0)) {
if (opts[k] && getType(opts[k]) !== getType(empty)) {
opts[k] = empty;
}
}
});
if (opts['disabled']) {
opts['disabledFlip'] = self.arrayFlip(opts['disabled'], true);
} else {
opts['disabledFlip'] = {};
}
return opts;
},
filter = function(file, asMap, type) {
var res = asMap? file : true,
ign = asMap? null : false,
vid, targetOptions, isRoot, rootNames;
if (file && file.hash && file.name && file.mime) {
if (file.mime === 'application/x-empty') {
file.mime = 'text/plain';
}
isRoot = self.isRoot(file);
if (isRoot && ! file.volumeid) {
self.debug('warning', 'The volume root statuses requires `volumeid` property.');
}
if (isRoot || file.mime === 'directory') {
// Prevention of circular reference
if (file.phash) {
if (file.phash === file.hash) {
error = error.concat(['Parent folder of "$1" is itself.', file.name]);
return ign;
}
if (isRoot && file.volumeid && file.phash.indexOf(file.volumeid) === 0) {
error = error.concat(['Parent folder of "$1" is inner itself.', file.name]);
return ign;
}
}
// set options, tmbUrls for each volume
if (file.volumeid) {
vid = file.volumeid;
if (isRoot) {
// make or update of leaf roots cache
if (file.phash) {
if (! self.leafRoots[file.phash]) {
self.leafRoots[file.phash] = [ file.hash ];
} else {
if ($.inArray(file.hash, self.leafRoots[file.phash]) === -1) {
self.leafRoots[file.phash].push(file.hash);
}
}
}
self.hasVolOptions = true;
if (! self.volOptions[vid]) {
self.volOptions[vid] = {
// set dispInlineRegex
dispInlineRegex: self.options.dispInlineRegex
};
}
targetOptions = self.volOptions[vid];
if (file.options) {
// >= v.2.1.14 has file.options
Object.assign(targetOptions, file.options);
}
// for compat <= v2.1.13
if (file.disabled) {
targetOptions.disabled = file.disabled;
targetOptions.disabledFlip = self.arrayFlip(file.disabled, true);
}
if (file.tmbUrl) {
targetOptions.tmbUrl = file.tmbUrl;
}
// '/' required at the end of url
if (targetOptions.url && targetOptions.url.substr(-1) !== '/') {
targetOptions.url += '/';
}
// check uiCmdMap
chkCmdMap(targetOptions);
// check trash bin hash
if (targetOptions.trashHash) {
if (self.trashes[targetOptions.trashHash] === false) {
delete targetOptions.trashHash;
} else {
self.trashes[targetOptions.trashHash] = file.hash;
}
}
// set immediate properties
$.each(self.optionProperties, function(k) {
if (targetOptions[k]) {
file[k] = targetOptions[k];
}
});
// regist fm.roots
if (type !== 'cwd') {
self.roots[vid] = file.hash;
}
// regist fm.volumeExpires
if (file.expires) {
self.volumeExpires[vid] = file.expires;
}
}
if (prevId !== vid) {
prevId = vid;
i18nFolderName = self.option('i18nFolderName', vid);
}
}
// volume root i18n name
if (isRoot && ! file.i18) {
name = 'volume_' + file.name,
i18 = self.i18n(false, name);
if (name !== i18) {
file.i18 = i18;
}
}
// i18nFolderName
if (i18nFolderName && ! file.i18) {
name = 'folder_' + file.name,
i18 = self.i18n(false, name);
if (name !== i18) {
file.i18 = i18;
}
}
if (isRoot) {
if (rootNames = self.storage('rootNames')) {
if (rootNames[file.hash]) {
file._name = file.name;
file._i18 = file.i18;
file.name = rootNames[file.hash] = rootNames[file.hash];
delete file.i18;
}
self.storage('rootNames', rootNames);
}
}
// lock trash bins holder
if (self.trashes[file.hash]) {
file.locked = true;
}
} else {
if (fileFilter) {
try {
if (! fileFilter(file)) {
return ign;
}
} catch(e) {
self.debug(e);
}
}
if (file.size == 0) {
file.mime = self.getMimetype(file.name, file.mime);
}
}
if (file.options) {
self.optionsByHashes[file.hash] = normalizeOptions(file.options);
}
delete file.options;
return res;
}
return ign;
},
getDescendants = function(hashes) {
var res = [];
$.each(self.files(), function(h, f) {
$.each(self.parents(h), function(i, ph) {
if ($.inArray(ph, hashes) !== -1 && $.inArray(h, hashes) === -1) {
res.push(h);
return false;
}
});
});
return res;
},
applyLeafRootStats = function(dataArr, type) {
$.each(dataArr, function(i, f) {
var pfile, done;
if (self.leafRoots[f.hash]) {
self.applyLeafRootStats(f);
}
// update leaf root parent stat
if (type !== 'change' && f.phash && self.isRoot(f) && (pfile = self.file(f.phash))) {
self.applyLeafRootStats(pfile);
// add to data.changed
if (!data.changed) {
data.changed = [pfile];
} else {
$.each(data.changed, function(i, f) {
if (f.hash === pfile.hash) {
data.changed[i] = pfile;
done = true;
return false;
}
});
if (!done) {
data.changed.push(pfile);
}
}
}
});
},
error = [],
name, i18, i18nFolderName, prevId, cData;
// set cunstom data
if (data.customData && data.customData !== self.prevCustomData) {
self.prevCustomData = data.customData;
try {
cData = JSON.parse(data.customData);
if ($.isPlainObject(cData)) {
self.prevCustomData = cData;
$.each(Object.keys(cData), function(i, key) {
if (cData[key] === null) {
delete cData[key];
delete self.optsCustomData[key];
}
});
self.customData = Object.assign({}, self.optsCustomData, cData);
}
} catch(e) {}
}
if (data.options) {
normalizeOptions(data.options);
}
if (data.cwd) {
if (data.cwd.volumeid && data.options && Object.keys(data.options).length && self.isRoot(data.cwd)) {
self.hasVolOptions = true;
self.volOptions[data.cwd.volumeid] = data.options;
}
data.cwd = filter(data.cwd, true, 'cwd');
}
if (data.files) {
data.files = $.grep(data.files, filter);
}
if (data.tree) {
data.tree = $.grep(data.tree, filter);
}
if (data.added) {
data.added = $.grep(data.added, filter);
}
if (data.changed) {
data.changed = $.grep(data.changed, filter);
}
if (data.removed && data.removed.length && self.searchStatus.state === 2) {
data.removed = data.removed.concat(getDescendants(data.removed));
}
if (data.api) {
data.init = true;
}
if (Object.keys(self.leafRoots).length) {
data.files && applyLeafRootStats(data.files);
data.tree && applyLeafRootStats(data.tree);
data.added && applyLeafRootStats(data.added);
data.changed && applyLeafRootStats(data.changed, 'change');
}
// merge options that apply only to cwd
if (data.cwd && data.cwd.options && data.options) {
Object.assign(data.options, normalizeOptions(data.cwd.options));
}
// '/' required at the end of url
if (data.options && data.options.url && data.options.url.substr(-1) !== '/') {
data.options.url += '/';
}
// check error
if (error.length) {
data.norError = ['errResponse'].concat(error);
}
return data;
},
/**
* Update sort options
*
* @param {String} sort type
* @param {String} sort order
* @param {Boolean} show folder first
*/
setSort : function(type, order, stickFolders, alsoTreeview) {
this.storage('sortType', (this.sortType = this.sortRules[type] ? type : 'name'));
this.storage('sortOrder', (this.sortOrder = /asc|desc/.test(order) ? order : 'asc'));
this.storage('sortStickFolders', (this.sortStickFolders = !!stickFolders) ? 1 : '');
this.storage('sortAlsoTreeview', (this.sortAlsoTreeview = !!alsoTreeview) ? 1 : '');
this.trigger('sortchange');
},
_sortRules : {
name : function(file1, file2) {
return elFinder.prototype.naturalCompare(file1.i18 || file1.name, file2.i18 || file2.name);
},
size : function(file1, file2) {
var size1 = parseInt(file1.size) || 0,
size2 = parseInt(file2.size) || 0;
return size1 === size2 ? 0 : size1 > size2 ? 1 : -1;
},
kind : function(file1, file2) {
return elFinder.prototype.naturalCompare(file1.mime, file2.mime);
},
date : function(file1, file2) {
var date1 = file1.ts || file1.date || 0,
date2 = file2.ts || file2.date || 0;
return date1 === date2 ? 0 : date1 > date2 ? 1 : -1;
},
perm : function(file1, file2) {
var val = function(file) { return (file.write? 2 : 0) + (file.read? 1 : 0); },
v1 = val(file1),
v2 = val(file2);
return v1 === v2 ? 0 : v1 > v2 ? 1 : -1;
},
mode : function(file1, file2) {
var v1 = file1.mode || (file1.perm || ''),
v2 = file2.mode || (file2.perm || '');
return elFinder.prototype.naturalCompare(v1, v2);
},
owner : function(file1, file2) {
var v1 = file1.owner || '',
v2 = file2.owner || '';
return elFinder.prototype.naturalCompare(v1, v2);
},
group : function(file1, file2) {
var v1 = file1.group || '',
v2 = file2.group || '';
return elFinder.prototype.naturalCompare(v1, v2);
}
},
/**
* Valid sort rule names
*
* @type Object
*/
sorters : {},
/**
* Compare strings for natural sort
*
* @param String
* @param String
* @return Number
*/
naturalCompare : function(a, b) {
var self = elFinder.prototype.naturalCompare;
if (typeof self.loc == 'undefined') {
self.loc = (navigator.userLanguage || navigator.browserLanguage || navigator.language || 'en-US');
}
if (typeof self.sort == 'undefined') {
if ('11'.localeCompare('2', self.loc, {numeric: true}) > 0) {
// Native support
if (window.Intl && window.Intl.Collator) {
self.sort = new Intl.Collator(self.loc, {numeric: true}).compare;
} else {
self.sort = function(a, b) {
return a.localeCompare(b, self.loc, {numeric: true});
};
}
} else {
/*
* Edited for elFinder (emulates localeCompare() by numeric) by Naoki Sawada aka nao-pon
*/
/*
* Huddle/javascript-natural-sort (https://github.com/Huddle/javascript-natural-sort)
*/
/*
* Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license
* Author: Jim Palmer (based on chunking idea from Dave Koelle)
* http://opensource.org/licenses/mit-license.php
*/
self.sort = function(a, b) {
var re = /(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi,
sre = /(^[ ]*|[ ]*$)/g,
dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
hre = /^0x[0-9a-f]+$/i,
ore = /^0/,
syre = /^[\x01\x21-\x2f\x3a-\x40\x5b-\x60\x7b-\x7e]/, // symbol first - (Naoki Sawada)
i = function(s) { return self.sort.insensitive && (''+s).toLowerCase() || ''+s; },
// convert all to strings strip whitespace
// first character is "_", it's smallest - (Naoki Sawada)
x = i(a).replace(sre, '').replace(/^_/, "\x01") || '',
y = i(b).replace(sre, '').replace(/^_/, "\x01") || '',
// chunk/tokenize
xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
// numeric, hex or date detection
xD = parseInt(x.match(hre)) || (xN.length != 1 && x.match(dre) && Date.parse(x)),
yD = parseInt(y.match(hre)) || xD && y.match(dre) && Date.parse(y) || null,
oFxNcL, oFyNcL,
locRes = 0;
// first try and sort Hex codes or Dates
if (yD) {
if ( xD < yD ) return -1;
else if ( xD > yD ) return 1;
}
// natural sorting through split numeric strings and default strings
for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) {
// find floats not starting with '0', string or 0 if not defined (Clint Priest)
oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0;
oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0;
// handle numeric vs string comparison - number < string - (Kyle Adams)
// but symbol first < number - (Naoki Sawada)
if (isNaN(oFxNcL) !== isNaN(oFyNcL)) {
if (isNaN(oFxNcL) && (typeof oFxNcL !== 'string' || ! oFxNcL.match(syre))) {
return 1;
} else if (typeof oFyNcL !== 'string' || ! oFyNcL.match(syre)) {
return -1;
}
}
// use decimal number comparison if either value is string zero
if (parseInt(oFxNcL, 10) === 0) oFxNcL = 0;
if (parseInt(oFyNcL, 10) === 0) oFyNcL = 0;
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
if (typeof oFxNcL !== typeof oFyNcL) {
oFxNcL += '';
oFyNcL += '';
}
// use locale sensitive sort for strings when case insensitive
// note: localeCompare interleaves uppercase with lowercase (e.g. A,a,B,b)
if (self.sort.insensitive && typeof oFxNcL === 'string' && typeof oFyNcL === 'string') {
locRes = oFxNcL.localeCompare(oFyNcL, self.loc);
if (locRes !== 0) return locRes;
}
if (oFxNcL < oFyNcL) return -1;
if (oFxNcL > oFyNcL) return 1;
}
return 0;
};
self.sort.insensitive = true;
}
}
return self.sort(a, b);
},
/**
* Compare files based on elFinder.sort
*
* @param Object file
* @param Object file
* @return Number
*/
compare : function(file1, file2) {
var self = this,
type = self.sortType,
asc = self.sortOrder == 'asc',
stick = self.sortStickFolders,
rules = self.sortRules,
sort = rules[type],
d1 = file1.mime == 'directory',
d2 = file2.mime == 'directory',
res;
if (stick) {
if (d1 && !d2) {
return -1;
} else if (!d1 && d2) {
return 1;
}
}
res = asc ? sort(file1, file2) : sort(file2, file1);
return type !== 'name' && res === 0
? res = asc ? rules.name(file1, file2) : rules.name(file2, file1)
: res;
},
/**
* Sort files based on config
*
* @param Array files
* @return Array
*/
sortFiles : function(files) {
return files.sort(this.compare);
},
/**
* Open notification dialog
* and append/update message for required notification type.
*
* @param Object options
* @example
* this.notify({
* type : 'copy',
* msg : 'Copy files', // not required for known types @see this.notifyType
* cnt : 3,
* hideCnt : false, // true for not show count
* progress : 10, // progress bar percents (use cnt : 0 to update progress bar)
* cancel : callback // callback function for cancel button
* })
* @return elFinder
*/
notify : function(opts) {
var type = opts.type,
id = opts.id? 'elfinder-notify-'+opts.id : '',
msg = this.i18n((typeof opts.msg !== 'undefined')? opts.msg : (this.messages['ntf'+type] ? 'ntf'+type : 'ntfsmth')),
ndialog = this.ui.notify,
notify = ndialog.children('.elfinder-notify-'+type+(id? ('.'+id) : '')),
button = notify.children('div.elfinder-notify-cancel').children('button'),
ntpl = '<div class="elfinder-notify elfinder-notify-{type}'+(id? (' '+id) : '')+'"><span class="elfinder-dialog-icon elfinder-dialog-icon-{type}"/><span class="elfinder-notify-msg">{msg}</span> <span class="elfinder-notify-cnt"/><div class="elfinder-notify-progressbar"><div class="elfinder-notify-progress"/></div><div class="elfinder-notify-cancel"/></div>',
delta = opts.cnt,
size = (typeof opts.size != 'undefined')? parseInt(opts.size) : null,
progress = (typeof opts.progress != 'undefined' && opts.progress >= 0) ? opts.progress : null,
cancel = opts.cancel,
clhover = 'ui-state-hover',
close = function() {
notify._esc && $(document).off('keydown', notify._esc);
notify.remove();
!ndialog.children().length && ndialog.elfinderdialog('close');
},
cnt, total, prc;
if (!type) {
return this;
}
if (!notify.length) {
notify = $(ntpl.replace(/\{type\}/g, type).replace(/\{msg\}/g, msg))
.appendTo(ndialog)
.data('cnt', 0);
if (progress != null) {
notify.data({progress : 0, total : 0});
}
if (cancel) {
button = $('<button type="button" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only"><span class="ui-button-text">'+this.i18n('btnCancel')+'</span></button>')
.on('mouseenter mouseleave', function(e) {
$(this).toggleClass(clhover, e.type === 'mouseenter');
});
notify.children('div.elfinder-notify-cancel').append(button);
}
} else if (typeof opts.msg !== 'undefined') {
notify.children('span.elfinder-notify-msg').html(msg);
}
cnt = delta + parseInt(notify.data('cnt'));
if (cnt > 0) {
if (cancel && button.length) {
if ($.isFunction(cancel) || (typeof cancel === 'object' && cancel.promise)) {
notify._esc = function(e) {
if (e.type == 'keydown' && e.keyCode != $.ui.keyCode.ESCAPE) {
return;
}
e.preventDefault();
e.stopPropagation();
close();
if (cancel.promise) {
cancel.reject(0); // 0 is canceling flag
} else {
cancel(e);
}
};
button.on('click', function(e) {
notify._esc(e);
});
$(document).on('keydown.' + this.namespace, notify._esc);
}
}
!opts.hideCnt && notify.children('.elfinder-notify-cnt').text('('+cnt+')');
ndialog.is(':hidden') && ndialog.elfinderdialog('open', this).height('auto');
notify.data('cnt', cnt);
if ((progress != null)
&& (total = notify.data('total')) >= 0
&& (prc = notify.data('progress')) >= 0) {
total += size != null? size : delta;
prc += progress;
(size == null && delta < 0) && (prc += delta * 100);
notify.data({progress : prc, total : total});
if (size != null) {
prc *= 100;
total = Math.max(1, total);
}
progress = parseInt(prc/total);
notify.find('.elfinder-notify-progress')
.animate({
width : (progress < 100 ? progress : 100)+'%'
}, 20);
}
} else {
close();
}
return this;
},
/**
* Open confirmation dialog
*
* @param Object options
* @example
* this.confirm({
* cssClass : 'elfinder-confirm-mydialog',
* title : 'Remove files',
* text : 'Here is question text',
* accept : { // accept callback - required
* label : 'Continue',
* callback : function(applyToAll) { fm.log('Ok') }
* },
* cancel : { // cancel callback - required
* label : 'Cancel',
* callback : function() { fm.log('Cancel')}
* },
* reject : { // reject callback - optionally
* label : 'No',
* callback : function(applyToAll) { fm.log('No')}
* },
* buttons : [ // additional buttons callback - optionally
* {
* label : 'Btn1',
* callback : function(applyToAll) { fm.log('Btn1')}
* }
* ],
* all : true // display checkbox "Apply to all"
* })
* @return elFinder
*/
confirm : function(opts) {
var self = this,
complete = false,
options = {
cssClass : 'elfinder-dialog-confirm',
modal : true,
resizable : false,
title : this.i18n(opts.title || 'confirmReq'),
buttons : {},
close : function() {
!complete && opts.cancel.callback();
$(this).elfinderdialog('destroy');
}
},
apply = this.i18n('apllyAll'),
label, checkbox, btnNum;
if (opts.cssClass) {
options.cssClass += ' ' + opts.cssClass;
}
options.buttons[this.i18n(opts.accept.label)] = function() {
opts.accept.callback(!!(checkbox && checkbox.prop('checked')));
complete = true;
$(this).elfinderdialog('close');
};
options.buttons[this.i18n(opts.accept.label)]._cssClass = 'elfinder-confirm-accept';
if (opts.reject) {
options.buttons[this.i18n(opts.reject.label)] = function() {
opts.reject.callback(!!(checkbox && checkbox.prop('checked')));
complete = true;
$(this).elfinderdialog('close');
};
options.buttons[this.i18n(opts.reject.label)]._cssClass = 'elfinder-confirm-reject';
}
if (opts.buttons && opts.buttons.length > 0) {
btnNum = 1;
$.each(opts.buttons, function(i, v){
options.buttons[self.i18n(v.label)] = function() {
v.callback(!!(checkbox && checkbox.prop('checked')));
complete = true;
$(this).elfinderdialog('close');
};
options.buttons[self.i18n(v.label)]._cssClass = 'elfinder-confirm-extbtn' + (btnNum++);
if (v.cssClass) {
options.buttons[self.i18n(v.label)]._cssClass += ' ' + v.cssClass;
}
});
}
options.buttons[this.i18n(opts.cancel.label)] = function() {
$(this).elfinderdialog('close');
};
options.buttons[this.i18n(opts.cancel.label)]._cssClass = 'elfinder-confirm-cancel';
if (opts.all) {
options.create = function() {
var base = $('<div class="elfinder-dialog-confirm-applyall"/>');
checkbox = $('<input type="checkbox" />');
$(this).next().find('.ui-dialog-buttonset')
.prepend(base.append($('<label>'+apply+'</label>').prepend(checkbox)));
};
}
if (opts.optionsCallback && $.isFunction(opts.optionsCallback)) {
opts.optionsCallback(options);
}
return this.dialog('<span class="elfinder-dialog-icon elfinder-dialog-icon-confirm"/>' + this.i18n(opts.text), options);
},
/**
* Create unique file name in required dir
*
* @param String file name
* @param String parent dir hash
* @param String glue
* @return String
*/
uniqueName : function(prefix, phash, glue) {
var i = 0, ext = '', p, name;
prefix = this.i18n(false, prefix);
phash = phash || this.cwd().hash;
glue = (typeof glue === 'undefined')? ' ' : glue;
if (p = prefix.match(/^(.+)(\.[^.]+)$/)) {
ext = p[2];
prefix = p[1];
}
name = prefix+ext;
if (!this.fileByName(name, phash)) {
return name;
}
while (i < 10000) {
name = prefix + glue + (++i) + ext;
if (!this.fileByName(name, phash)) {
return name;
}
}
return prefix + Math.random() + ext;
},
/**
* Return message translated onto current language
* Allowed accept HTML element that was wrapped in jQuery object
* To be careful to XSS vulnerability of HTML element Ex. You should use `fm.escape(file.name)`
*
* @param String|Array message[s]|Object jQuery
* @return String
**/
i18n : function() {
var self = this,
messages = this.messages,
input = [],
ignore = [],
message = function(m) {
var file;
if (m.indexOf('#') === 0) {
if ((file = self.file(m.substr(1)))) {
return file.name;
}
}
return m;
},
i, j, m, escFunc, start = 0, isErr;
if (arguments.length && arguments[0] === false) {
escFunc = function(m){ return m; };
start = 1;
}
for (i = start; i< arguments.length; i++) {
m = arguments[i];
if (Array.isArray(m)) {
for (j = 0; j < m.length; j++) {
if (m[j] instanceof jQuery) {
// jQuery object is HTML element
input.push(m[j]);
} else if (typeof m[j] !== 'undefined'){
input.push(message('' + m[j]));
}
}
} else if (m instanceof jQuery) {
// jQuery object is HTML element
input.push(m[j]);
} else if (typeof m !== 'undefined'){
input.push(message('' + m));
}
}
for (i = 0; i < input.length; i++) {
// dont translate placeholders
if ($.inArray(i, ignore) !== -1) {
continue;
}
m = input[i];
if (typeof m == 'string') {
isErr = !!(messages[m] && m.match(/^err/));
// translate message
m = messages[m] || (escFunc? escFunc(m) : self.escape(m));
// replace placeholders in message
m = m.replace(/\$(\d+)/g, function(match, placeholder) {
var res;
placeholder = i + parseInt(placeholder);
if (placeholder > 0 && input[placeholder]) {
ignore.push(placeholder);
}
res = escFunc? escFunc(input[placeholder]) : self.escape(input[placeholder]);
if (isErr) {
res = '<span class="elfinder-err-var elfinder-err-var' + placeholder + '">' + res + '</span>';
}
return res;
});
} else {
// get HTML from jQuery object
m = m.get(0).outerHTML;
}
input[i] = m;
}
return $.grep(input, function(m, i) { return $.inArray(i, ignore) === -1 ? true : false; }).join('<br>');
},
/**
* Get icon style from file.icon
*
* @param Object elFinder file object
* @return String|Object
*/
getIconStyle : function(file, asObject) {
var self = this,
template = {
'background' : 'url(\'{url}\') 0 0 no-repeat',
'background-size' : 'contain'
},
style = '',
cssObj = {},
i = 0;
if (file.icon) {
style = 'style="';
$.each(template, function(k, v) {
if (i++ === 0) {
v = v.replace('{url}', self.escape(file.icon));
}
if (asObject) {
cssObj[k] = v;
} else {
style += k+':'+v+';';
}
});
style += '"';
}
return asObject? cssObj : style;
},
/**
* Convert mimetype into css classes
*
* @param String file mimetype
* @return String
*/
mime2class : function(mimeType) {
var prefix = 'elfinder-cwd-icon-',
mime = mimeType.toLowerCase(),
isText = this.textMimes[mime];
mime = mime.split('/');
if (isText) {
mime[0] += ' ' + prefix + 'text';
} else if (mime[1] && mime[1].match(/\+xml$/)) {
mime[0] += ' ' + prefix + 'xml';
}
return prefix + mime[0] + (mime[1] ? ' ' + prefix + mime[1].replace(/(\.|\+)/g, '-') : '');
},
/**
* Return localized kind of file
*
* @param Object|String file or file mimetype
* @return String
*/
mime2kind : function(f) {
var isObj = typeof(f) == 'object' ? true : false,
mime = isObj ? f.mime : f,
kind;
if (isObj && f.alias && mime != 'symlink-broken') {
kind = 'Alias';
} else if (this.kinds[mime]) {
if (isObj && mime === 'directory' && (! f.phash || f.isroot)) {
kind = 'Root';
} else {
kind = this.kinds[mime];
}
}
if (! kind) {
if (mime.indexOf('text') === 0) {
kind = 'Text';
} else if (mime.indexOf('image') === 0) {
kind = 'Image';
} else if (mime.indexOf('audio') === 0) {
kind = 'Audio';
} else if (mime.indexOf('video') === 0) {
kind = 'Video';
} else if (mime.indexOf('application') === 0) {
kind = 'App';
} else {
kind = mime;
}
}
return this.messages['kind'+kind] ? this.i18n('kind'+kind) : mime;
},
/**
* Return boolean Is mime-type text file
*
* @param String mime-type
* @return Boolean
*/
mimeIsText : function(mime) {
return (this.textMimes[mime.toLowerCase()] || (mime.indexOf('text/') === 0 && mime.substr(5, 3) !== 'rtf') || mime.match(/^application\/.+\+xml$/))? true : false;
},
/**
* Returns a date string formatted according to the given format string
*
* @param String format string
* @param Object Date object
* @return String
*/
date : function(format, date) {
var self = this,
output, d, dw, m, y, h, g, i, s;
if (! date) {
date = new Date();
}
h = date[self.getHours]();
g = h > 12 ? h - 12 : h;
i = date[self.getMinutes]();
s = date[self.getSeconds]();
d = date[self.getDate]();
dw = date[self.getDay]();
m = date[self.getMonth]() + 1;
y = date[self.getFullYear]();
output = format.replace(/[a-z]/gi, function(val) {
switch (val) {
case 'd': return d > 9 ? d : '0'+d;
case 'j': return d;
case 'D': return self.i18n(self.i18.daysShort[dw]);
case 'l': return self.i18n(self.i18.days[dw]);
case 'm': return m > 9 ? m : '0'+m;
case 'n': return m;
case 'M': return self.i18n(self.i18.monthsShort[m-1]);
case 'F': return self.i18n(self.i18.months[m-1]);
case 'Y': return y;
case 'y': return (''+y).substr(2);
case 'H': return h > 9 ? h : '0'+h;
case 'G': return h;
case 'g': return g;
case 'h': return g > 9 ? g : '0'+g;
case 'a': return h >= 12 ? 'pm' : 'am';
case 'A': return h >= 12 ? 'PM' : 'AM';
case 'i': return i > 9 ? i : '0'+i;
case 's': return s > 9 ? s : '0'+s;
}
return val;
});
return output;
},
/**
* Return localized date
*
* @param Object file object
* @return String
*/
formatDate : function(file, t) {
var self = this,
ts = t || file.ts,
i18 = self.i18,
date, format, output, d, dw, m, y, h, g, i, s;
if (self.options.clientFormatDate && ts > 0) {
date = new Date(ts*1000);
format = ts >= this.yesterday
? this.fancyFormat
: this.dateFormat;
output = self.date(format, date);
return ts >= this.yesterday
? output.replace('$1', this.i18n(ts >= this.today ? 'Today' : 'Yesterday'))
: output;
} else if (file.date) {
return file.date.replace(/([a-z]+)\s/i, function(a1, a2) { return self.i18n(a2)+' '; });
}
return self.i18n('dateUnknown');
},
/**
* Return localized number string
*
* @param Number
* @return String
*/
toLocaleString : function(num) {
var v = new Number(num);
if (v) {
if (v.toLocaleString) {
return v.toLocaleString();
} else {
return String(num).replace( /(\d)(?=(\d\d\d)+(?!\d))/g, '$1,');
}
}
return num;
},
/**
* Return css class marks file permissions
*
* @param Object file
* @return String
*/
perms2class : function(o) {
var c = '';
if (!o.read && !o.write) {
c = 'elfinder-na';
} else if (!o.read) {
c = 'elfinder-wo';
} else if (!o.write) {
c = 'elfinder-ro';
}
if (o.type) {
c += ' elfinder-' + this.escape(o.type);
}
return c;
},
/**
* Return localized string with file permissions
*
* @param Object file
* @return String
*/
formatPermissions : function(f) {
var p = [];
f.read && p.push(this.i18n('read'));
f.write && p.push(this.i18n('write'));
return p.length ? p.join(' '+this.i18n('and')+' ') : this.i18n('noaccess');
},
/**
* Return formated file size
*
* @param Number file size
* @return String
*/
formatSize : function(s) {
var n = 1, u = 'b';
if (s == 'unknown') {
return this.i18n('unknown');
}
if (s > 1073741824) {
n = 1073741824;
u = 'GB';
} else if (s > 1048576) {
n = 1048576;
u = 'MB';
} else if (s > 1024) {
n = 1024;
u = 'KB';
}
s = s/n;
return (s > 0 ? n >= 1048576 ? s.toFixed(2) : Math.round(s) : 0) +' '+u;
},
/**
* Return formated file mode by options.fileModeStyle
*
* @param String file mode
* @param String format style
* @return String
*/
formatFileMode : function(p, style) {
var i, o, s, b, sticy, suid, sgid, str, oct;
if (!style) {
style = this.options.fileModeStyle.toLowerCase();
}
p = $.trim(p);
if (p.match(/[rwxs-]{9}$/i)) {
str = p = p.substr(-9);
if (style == 'string') {
return str;
}
oct = '';
s = 0;
for (i=0; i<7; i=i+3) {
o = p.substr(i, 3);
b = 0;
if (o.match(/[r]/i)) {
b += 4;
}
if (o.match(/[w]/i)) {
b += 2;
}
if (o.match(/[xs]/i)) {
if (o.match(/[xs]/)) {
b += 1;
}
if (o.match(/[s]/i)) {
if (i == 0) {
s += 4;
} else if (i == 3) {
s += 2;
}
}
}
oct += b.toString(8);
}
if (s) {
oct = s.toString(8) + oct;
}
} else {
p = parseInt(p, 8);
oct = p? p.toString(8) : '';
if (!p || style == 'octal') {
return oct;
}
o = p.toString(8);
s = 0;
if (o.length > 3) {
o = o.substr(-4);
s = parseInt(o.substr(0, 1), 8);
o = o.substr(1);
}
sticy = ((s & 1) == 1); // not support
sgid = ((s & 2) == 2);
suid = ((s & 4) == 4);
str = '';
for(i=0; i<3; i++) {
if ((parseInt(o.substr(i, 1), 8) & 4) == 4) {
str += 'r';
} else {
str += '-';
}
if ((parseInt(o.substr(i, 1), 8) & 2) == 2) {
str += 'w';
} else {
str += '-';
}
if ((parseInt(o.substr(i, 1), 8) & 1) == 1) {
str += ((i==0 && suid)||(i==1 && sgid))? 's' : 'x';
} else {
str += '-';
}
}
}
if (style == 'both') {
return str + ' (' + oct + ')';
} else if (style == 'string') {
return str;
} else {
return oct;
}
},
/**
* Regist this.decodeRawString function
*
* @return void
*/
registRawStringDecoder : function(rawStringDecoder) {
if ($.isFunction(rawStringDecoder)) {
this.decodeRawString = this.options.rawStringDecoder = rawStringDecoder;
}
},
/**
* Return boolean that uploadable MIME type into target folder
*
* @param String mime MIME type
* @param String target target folder hash
* @return Bool
*/
uploadMimeCheck : function(mime, target) {
target = target || this.cwd().hash;
var res = true, // default is allow
mimeChecker = this.option('uploadMime', target),
allow,
deny,
check = function(checker) {
var ret = false;
if (typeof checker === 'string' && checker.toLowerCase() === 'all') {
ret = true;
} else if (Array.isArray(checker) && checker.length) {
$.each(checker, function(i, v) {
v = v.toLowerCase();
if (v === 'all' || mime.indexOf(v) === 0) {
ret = true;
return false;
}
});
}
return ret;
};
if (mime && $.isPlainObject(mimeChecker)) {
mime = mime.toLowerCase();
allow = check(mimeChecker.allow);
deny = check(mimeChecker.deny);
if (mimeChecker.firstOrder === 'allow') {
res = false; // default is deny
if (! deny && allow === true) { // match only allow
res = true;
}
} else {
res = true; // default is allow
if (deny === true && ! allow) { // match only deny
res = false;
}
}
}
return res;
},
/**
* call chained sequence of async deferred functions
*
* @param Array tasks async functions
* @return Object jQuery.Deferred
*/
sequence : function(tasks) {
var l = tasks.length,
chain = function(task, idx) {
++idx;
if (tasks[idx]) {
return chain(task.then(tasks[idx]), idx);
} else {
return task;
}
};
if (l > 1) {
return chain(tasks[0](), 0);
} else {
return tasks[0]();
}
},
/**
* Reload contents of target URL for clear browser cache
*
* @param String url target URL
* @return Object jQuery.Deferred
*/
reloadContents : function(url) {
var dfd = $.Deferred(),
ifm;
try {
ifm = $('<iframe width="1" height="1" scrolling="no" frameborder="no" style="position:absolute; top:-1px; left:-1px" crossorigin="use-credentials">')
.attr('src', url)
.one('load', function() {
var ifm = $(this);
try {
this.contentDocument.location.reload(true);
ifm.one('load', function() {
ifm.remove();
dfd.resolve();
});
} catch(e) {
ifm.attr('src', '').attr('src', url).one('load', function() {
ifm.remove();
dfd.resolve();
});
}
})
.appendTo('body');
} catch(e) {
ifm && ifm.remove();
dfd.reject();
}
return dfd;
},
/**
* Make netmount option for OAuth2
*
* @param String protocol
* @param String name
* @param String host
* @param Object opts Default {noOffline: false, root: 'root', pathI18n: 'folderId', folders: true}
}
*
* @return Object
*/
makeNetmountOptionOauth : function(protocol, name, host, opt) {
var noOffline = typeof opt === 'boolean'? opt : null, // for backward compat
opts = Object.assign({
noOffline : false,
root : 'root',
pathI18n : 'folderId',
folders : true
}, (noOffline === null? (opt || {}) : {noOffline : noOffline})),
addFolders = function(fm, bro, folders) {
var self = this,
cnt = Object.keys($.isPlainObject(folders)? folders : {}).length,
select;
bro.next().remove();
if (cnt) {
select = $('<select class="ui-corner-all elfinder-tabstop" style="max-width:200px;">').append(
$($.map(folders, function(n,i){return '<option value="'+fm.escape((i+'').trim())+'">'+fm.escape(n)+'</option>';}).join(''))
).on('change click', function(e){
var node = $(this),
path = node.val(),
spn;
self.inputs.path.val(path);
if (opts.folders && (e.type === 'change' || node.data('current') !== path)) {
node.next().remove();
node.data('current', path);
if (path != opts.root) {
spn = spinner();
if (xhr && xhr.state() === 'pending') {
fm.abortXHR(xhr, { quiet: true , abort: true });
}
node.after(spn);
xhr = fm.request({
data : {cmd : 'netmount', protocol: protocol, host: host, user: 'init', path: path, pass: 'folders'},
preventDefault : true
}).done(function(data){
addFolders.call(self, fm, node, data.folders);
}).always(function() {
fm.abortXHR(xhr, { quiet: true });
spn.remove();
}).xhr;
}
}
});
bro.after($('<div/>').append(select))
.closest('.ui-dialog').trigger('tabstopsInit');
select.trigger('focus');
}
},
spinner = function() {
return $('<div class="elfinder-netmount-spinner"/>').append('<span class="elfinder-spinner"/>');
},
xhr;
return {
vars : {},
name : name,
inputs: {
offline : $('<input type="checkbox"/>').on('change', function() {
$(this).parents('table.elfinder-netmount-tb').find('select:first').trigger('change', 'reset');
}),
host : $('<span><span class="elfinder-spinner"/></span><input type="hidden"/>'),
path : $('<input type="text" value="'+opts.root+'"/>'),
user : $('<input type="hidden"/>'),
pass : $('<input type="hidden"/>')
},
select: function(fm, ev, d){
var f = this.inputs,
oline = f.offline,
f0 = $(f.host[0]),
data = d || null;
this.vars.mbtn = f.host.closest('.ui-dialog').children('.ui-dialog-buttonpane:first').find('button.elfinder-btncnt-0');
if (! f0.data('inrequest')
&& (f0.find('span.elfinder-spinner').length
|| data === 'reset'
|| (data === 'winfocus' && ! f0.siblings('span.elfinder-button-icon-reload').length))
)
{
if (oline.parent().children().length === 1) {
f.path.parent().prev().html(fm.i18n(opts.pathI18n));
oline.attr('title', fm.i18n('offlineAccess'));
oline.uniqueId().after($('<label/>').attr('for', oline.attr('id')).html(' '+fm.i18n('offlineAccess')));
}
f0.data('inrequest', true).empty().addClass('elfinder-spinner')
.parent().find('span.elfinder-button-icon').remove();
fm.request({
data : {cmd : 'netmount', protocol: protocol, host: host, user: 'init', options: {id: fm.id, offline: oline.prop('checked')? 1:0, pass: f.host[1].value}},
preventDefault : true
}).done(function(data){
f0.removeClass("elfinder-spinner").html(data.body.replace(/\{msg:([^}]+)\}/g, function(whole,s1){return fm.i18n(s1, host);}));
});
opts.noOffline && oline.closest('tr').hide();
} else {
oline.closest('tr')[(opts.noOffline || f.user.val())? 'hide':'show']();
f0.data('funcexpup') && f0.data('funcexpup')();
}
this.vars.mbtn[$(f.host[1]).val()? 'show':'hide']();
},
done: function(fm, data){
var f = this.inputs,
p = this.protocol,
f0 = $(f.host[0]),
f1 = $(f.host[1]),
expires = '&nbsp;';
opts.noOffline && f.offline.closest('tr').hide();
if (data.mode == 'makebtn') {
f0.removeClass('elfinder-spinner').removeData('expires').removeData('funcexpup');
f.host.find('input').on('mouseenter mouseleave', function(){$(this).toggleClass('ui-state-hover');});
f1.val('');
f.path.val(opts.root).next().remove();
f.user.val('');
f.pass.val('');
! opts.noOffline && f.offline.closest('tr').show();
this.vars.mbtn.hide();
} else if (data.mode == 'folders') {
if (data.folders) {
addFolders.call(this, fm, f.path.nextAll(':last'), data.folders);
}
} else {
if (data.expires) {
expires = '()';
f0.data('expires', data.expires);
}
f0.html(host + expires).removeClass('elfinder-spinner');
if (data.expires) {
f0.data('funcexpup', function() {
var rem = Math.floor((f0.data('expires') - (+new Date()) / 1000) / 60);
if (rem < 3) {
f0.parent().children('.elfinder-button-icon-reload').click();
} else {
f0.text(f0.text().replace(/\(.*\)/, '('+fm.i18n(['minsLeft', rem])+')'));
setTimeout(function() {
if (f0.is(':visible')) {
f0.data('funcexpup')();
}
}, 60000);
}
});
f0.data('funcexpup')();
}
if (data.reset) {
p.trigger('change', 'reset');
return;
}
f0.parent().append($('<span class="elfinder-button-icon elfinder-button-icon-reload" title="'+fm.i18n('reAuth')+'">')
.on('click', function() {
f1.val('reauth');
p.trigger('change', 'reset');
}));
f1.val(protocol);
this.vars.mbtn.show();
if (data.folders) {
addFolders.call(this, fm, f.path, data.folders);
}
f.user.val('done');
f.pass.val('done');
f.offline.closest('tr').hide();
}
f0.removeData('inrequest');
},
fail: function(fm, err){
$(this.inputs.host[0]).removeData('inrequest');
this.protocol.trigger('change', 'reset');
},
integrateInfo: opts.integrate
};
},
/**
* Find cwd's nodes from files
*
* @param Array files
* @param Object opts {firstOnly: true|false}
*/
findCwdNodes : function(files, opts) {
var self = this,
cwd = this.getUI('cwd'),
cwdHash = this.cwd().hash,
newItem = $();
opts = opts || {};
$.each(files, function(i, f) {
if (f.phash === cwdHash || self.searchStatus.state > 1) {
newItem = newItem.add(cwd.find('#'+self.cwdHash2Id(f.hash)));
if (opts.firstOnly) {
return false;
}
}
});
return newItem;
},
/**
* Convert from relative URL to abstract URL based on current URL
*
* @param String URL
* @return String
*/
convAbsUrl : function(url) {
if (url.match(/^http/i)) {
return url;
}
if (url.substr(0,2) === '//') {
return window.location.protocol + url;
}
var root = window.location.protocol + '//' + window.location.host,
reg = /[^\/]+\/\.\.\//,
ret;
if (url.substr(0, 1) === '/') {
ret = root + url;
} else {
ret = root + window.location.pathname.replace(/\/[^\/]+$/, '/') + url;
}
ret = ret.replace('/./', '/');
while(reg.test(ret)) {
ret = ret.replace(reg, '');
}
return ret;
},
/**
* Is same origin to current site
*
* @param String check url
* @return Boolean
*/
isSameOrigin : function (checkUrl) {
var url;
checkUrl = this.convAbsUrl(checkUrl);
if (location.origin && window.URL) {
try {
url = new URL(checkUrl);
return location.origin === url.origin;
} catch(e) {}
}
url = document.createElement('a');
url.href = checkUrl;
return location.protocol === url.protocol && location.host === url.host && location.port && url.port;
},
navHash2Id : function(hash) {
return this.navPrefix + hash;
},
navId2Hash : function(id) {
return typeof(id) == 'string' ? id.substr(this.navPrefix.length) : false;
},
cwdHash2Id : function(hash) {
return this.cwdPrefix + hash;
},
cwdId2Hash : function(id) {
return typeof(id) == 'string' ? id.substr(this.cwdPrefix.length) : false;
},
isInWindow : function(elem, nochkHide) {
var elm, rect;
if (! (elm = elem.get(0))) {
return false;
}
if (! nochkHide && elm.offsetParent === null) {
return false;
}
rect = elm.getBoundingClientRect();
return document.elementFromPoint(rect.left, rect.top)? true : false;
},
/**
* calculate elFinder node z-index
*
* @return void
*/
zIndexCalc : function() {
var self = this,
node = this.getUI(),
ni = node.css('z-index');
if (ni && ni !== 'auto' && ni !== 'inherit') {
self.zIndex = ni;
} else {
node.parents().each(function(i, n) {
var z = $(n).css('z-index');
if (z !== 'auto' && z !== 'inherit' && (z = parseInt(z))) {
self.zIndex = z;
return false;
}
});
}
},
/**
* Load JavaScript files
*
* @param Array urls to load JavaScript file URLs
* @param Function callback call back function on script loaded
* @param Object opts Additional options to $.ajax OR {loadType: 'tag'} to load by script tag
* @param Object check { obj: (Object)ParentObject, name: (String)"Attribute name", timeout: (Integer)milliseconds }
* @return elFinder
*/
loadScript : function(urls, callback, opts, check) {
var defOpts = {
dataType : 'script',
cache : true
},
success, cnt, scripts = {}, results = {};
opts = opts || {};
if (opts.tryRequire && this.hasRequire) {
require(urls, callback, opts.error);
} else {
success = function() {
var cnt, fi, hasError;
$.each(results, function(i, status) {
if (status !== 'success' && status !== 'notmodified') {
hasError = true;
return false;
}
});
if (!hasError) {
if ($.isFunction(callback)) {
if (check) {
if (typeof check.obj[check.name] === 'undefined') {
cnt = check.timeout? (check.timeout / 10) : 1;
fi = setInterval(function() {
if (--cnt < 0 || typeof check.obj[check.name] !== 'undefined') {
clearInterval(fi);
callback();
}
}, 10);
} else {
callback();
}
} else {
callback();
}
}
} else {
if (opts.error && $.isFunction(opts.error)) {
opts.error({ loadResults: results });
}
}
};
if (opts.loadType === 'tag') {
$('head > script').each(function() {
scripts[this.src] = this;
});
cnt = urls.length;
$.each(urls, function(i, url) {
var done = false,
script;
if (scripts[url]) {
results[i] = scripts[url]._error || 'success';
(--cnt < 1) && success();
} else {
script = document.createElement('script');
script.charset = opts.charset || 'UTF-8';
$('head').append(script);
script.onload = script.onreadystatechange = function() {
if ( !done && (!this.readyState ||
this.readyState === 'loaded' || this.readyState === 'complete') ) {
done = true;
results[i] = 'success';
(--cnt < 1) && success();
}
};
script.onerror = function(err) {
results[i] = script._error = (err && err.type)? err.type : 'error';
(--cnt < 1) && success();
};
script.src = url;
}
});
} else {
opts = $.isPlainObject(opts)? Object.assign(defOpts, opts) : defOpts;
cnt = 0;
(function appendScript(d, status) {
if (d !== void(0)) {
results[cnt++] = status;
}
if (urls.length) {
$.ajax(Object.assign({}, opts, {
url: urls.shift(),
success: appendScript,
error: appendScript
}));
} else {
success();
}
})();
}
}
return this;
},
/**
* Load CSS files
*
* @param Array to load CSS file URLs
* @param Object options
* @return elFinder
*/
loadCss : function(urls, opts) {
var self = this,
clName, dfds;
if (typeof urls === 'string') {
urls = [ urls ];
}
if (opts) {
if (opts.className) {
clName = opts.className;
}
if (opts.dfd && opts.dfd.promise) {
dfds = [];
}
}
$.each(urls, function(i, url) {
var link, df;
url = self.convAbsUrl(url).replace(/^https?:/i, '');
if (dfds) {
dfds[i] = $.Deferred();
}
if (! $("head > link[href='+url+']").length) {
link = document.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
link.href = url;
if (clName) {
link.className = clName;
}
if (dfds) {
link.onload = function() {
dfds[i].resolve();
};
link.onerror = function() {
dfds[i].reject();
};
}
$('head').append(link);
} else {
dfds && dfds[i].resolve();
}
});
if (dfds) {
$.when.apply(null, dfds).done(function() {
opts.dfd.resolve();
}).fail(function() {
opts.dfd.reject();
});
}
return this;
},
/**
* Abortable async job performer
*
* @param func Function
* @param arr Array
* @param opts Object
*
* @return Object $.Deferred that has an extended method _abort()
*/
asyncJob : function(func, arr, opts) {
var dfrd = $.Deferred(),
abortFlg = false,
parms = Object.assign({
interval : 0,
numPerOnce : 1
}, opts || {}),
resArr = [],
vars =[],
curVars = [],
exec,
tm;
dfrd._abort = function(resolve) {
tm && clearTimeout(tm);
vars = [];
abortFlg = true;
if (dfrd.state() === 'pending') {
dfrd[resolve? 'resolve' : 'reject'](resArr);
}
};
dfrd.fail(function() {
dfrd._abort();
}).always(function() {
dfrd._abort = function() {};
});
if (typeof func === 'function' && Array.isArray(arr)) {
vars = arr.concat();
exec = function() {
var i, len, res;
if (abortFlg) {
return;
}
curVars = vars.splice(0, parms.numPerOnce);
len = curVars.length;
for (i = 0; i < len; i++) {
if (abortFlg) {
break;
}
res = func(curVars[i]);
(res !== null) && resArr.push(res);
}
if (abortFlg) {
return;
}
if (vars.length) {
tm = setTimeout(exec, parms.interval);
} else {
dfrd.resolve(resArr);
}
};
if (vars.length) {
tm = setTimeout(exec, 0);
} else {
dfrd.resolve(resArr);
}
} else {
dfrd.reject();
}
return dfrd;
},
getSize : function(targets) {
var self = this,
reqs = [],
tgtlen = targets.length,
dfrd = $.Deferred().fail(function() {
$.each(reqs, function(i, req) {
if (req) {
req.syncOnFail && req.syncOnFail(false);
req.reject();
}
});
}),
getLeafRoots = function(file) {
var targets = [];
if (file.mime === 'directory') {
$.each(self.leafRoots, function(hash, roots) {
var phash;
if (hash === file.hash) {
targets.push.apply(targets, roots);
} else {
phash = (self.file(hash) || {}).phash;
while(phash) {
if (phash === file.hash) {
targets.push.apply(targets, roots);
}
phash = (self.file(phash) || {}).phash;
}
}
});
}
return targets;
},
checkPhash = function(hash) {
var dfd = $.Deferred(),
dir = self.file(hash),
target = dir? dir.phash : hash;
if (target && ! self.file(target)) {
self.request({
data : {
cmd : 'parents',
target : target
},
preventFail : true
}).done(function() {
self.one('parentsdone', function() {
dfd.resolve();
});
}).fail(function() {
dfd.resolve();
});
} else {
dfd.resolve();
}
return dfd;
},
cache = function() {
var dfd = $.Deferred(),
cnt = Object.keys(self.leafRoots).length;
if (cnt > 0) {
$.each(self.leafRoots, function(hash) {
checkPhash(hash).done(function() {
--cnt;
if (cnt < 1) {
dfd.resolve();
}
});
});
} else {
dfd.resolve();
}
return dfd;
};
self.autoSync('stop');
cache().done(function() {
var files = [], grps = {}, dfds = [], cache = [], singles = {};
$.each(targets, function() {
files.push.apply(files, getLeafRoots(self.file(this)));
});
targets.push.apply(targets, files);
$.each(targets, function() {
var root = self.root(this),
file = self.file(this);
if (file && (file.sizeInfo || file.mime !== 'directory')) {
cache.push($.Deferred().resolve(file.sizeInfo? file.sizeInfo : {size: file.size, dirCnt: 0, fileCnt : 1}));
} else {
if (! grps[root]) {
grps[root] = [ this ];
} else {
grps[root].push(this);
}
}
});
$.each(grps, function() {
var idx = dfds.length;
if (this.length === 1) {
singles[idx] = this[0];
}
dfds.push(self.request({
data : {cmd : 'size', targets : this},
preventDefault : true
}));
});
reqs.push.apply(reqs, dfds);
dfds.push.apply(dfds, cache);
$.when.apply($, dfds).fail(function() {
dfrd.reject();
}).done(function() {
var cache = function(h, data) {
var file;
if (file = self.file(h)) {
file.sizeInfo = { isCache: true };
$.each(['size', 'dirCnt', 'fileCnt'], function() {
file.sizeInfo[this] = data[this] || 0;
});
file.size = parseInt(file.sizeInfo.size);
changed.push(file);
}
},
size = 0,
fileCnt = 0,
dirCnt = 0,
argLen = arguments.length,
cnts = [],
cntsTxt = '',
changed = [],
i, file, data;
for (i = 0; i < argLen; i++) {
data = arguments[i];
file = null;
if (!data.isCache) {
if (singles[i] && (file = self.file(singles[i]))) {
cache(singles[i], data);
} else if (data.sizes && $.isPlainObject(data.sizes)) {
$.each(data.sizes, function(h, sizeInfo) {
cache(h, sizeInfo);
});
}
}
size += parseInt(data.size);
if (fileCnt !== false) {
if (typeof data.fileCnt === 'undefined') {
fileCnt = false;
}
fileCnt += parseInt(data.fileCnt || 0);
}
if (dirCnt !== false) {
if (typeof data.dirCnt === 'undefined') {
dirCnt = false;
}
dirCnt += parseInt(data.dirCnt || 0);
}
}
changed.length && self.change({changed: changed});
if (dirCnt !== false){
cnts.push(self.i18n('folders') + ': ' + (dirCnt - (tgtlen > 1? 0 : 1)));
}
if (fileCnt !== false){
cnts.push(self.i18n('files') + ': ' + fileCnt);
}
if (cnts.length) {
cntsTxt = '<br>' + cnts.join(', ');
}
dfrd.resolve({
size: size,
fileCnt: fileCnt,
dirCnt: dirCnt,
formated: (size >= 0 ? self.formatSize(size) : self.i18n('unknown')) + cntsTxt
});
});
self.autoSync();
});
return dfrd;
},
/**
* Gets the theme object by settings of options.themes
*
* @param String themeid The themeid
* @return Object jQuery.Deferred
*/
getTheme : function(themeid) {
var self = this,
dfd = $.Deferred(),
absUrl = function(url, base) {
if (Array.isArray(url)) {
return $.map(url, function(v) {
return absUrl(v, base);
});
} else {
return url.match(/^(?:http|\/\/)/i)? url : (base || self.baseUrl) + url.replace(/^(?:\.\/|\/)/, '');
}
},
themeObj, m;
if (themeid && (themeObj = self.options.themes[themeid])) {
if (typeof themeObj === 'string') {
url = absUrl(themeObj);
if (m = url.match(/^(.+\/)[^/]+\.json$/i)) {
$.getJSON(url).done(function(data) {
themeObj = data;
themeObj.id = themeid;
if (themeObj.cssurls) {
themeObj.cssurls = absUrl(themeObj.cssurls, m[1]);
}
dfd.resolve(themeObj);
}).fail(function() {
dfd.reject();
});
} else {
dfd.resolve({
id: themeid,
name: themeid,
cssurls: [url]
});
}
} else if ($.isPlainObject(themeObj) && themeObj.cssurls) {
themeObj.id = themeid;
themeObj.cssurls = absUrl(themeObj.cssurls);
if (!Array.isArray(themeObj.cssurls)) {
themeObj.cssurls = [themeObj.cssurls];
}
if (!themeObj.name) {
themeObj.name = themeid;
}
dfd.resolve(themeObj);
} else {
dfd.reject();
}
} else {
dfd.reject();
}
return dfd;
},
/**
* Change current theme
*
* @param String themeid The themeid
* @return Object this elFinder instance
*/
changeTheme : function(themeid) {
var self = this;
if (themeid) {
if (self.options.themes[themeid] && (!self.theme || self.theme.id !== themeid)) {
self.getTheme(themeid).done(function(themeObj) {
if (themeObj.cssurls) {
$('head>link.elfinder-theme-ext').remove();
self.loadCss(themeObj.cssurls, {
className: 'elfinder-theme-ext',
dfd: $.Deferred().done(function() {
self.theme = themeObj;
self.trigger && self.trigger('themechange');
})
});
}
});
} else if (themeid === 'default' && self.theme) {
$('head>link.elfinder-theme-ext').remove();
self.theme = null;
self.trigger && self.trigger('themechange');
}
}
return this;
},
/**
* Apply leaf root stats to target directory
*
* @param object dir object of target directory
* @param boolean update is force update
*
* @return boolean dir object was chenged
*/
applyLeafRootStats : function(dir, update) {
var self = this,
prev = update? dir : (self.file(dir.hash) || dir),
prevTs = prev.ts,
change = false;
// backup original stats
if (update || !dir._realStats) {
dir._realStats = {
locked: dir.locked || 0,
dirs: dir.dirs || 0,
ts: dir.ts
};
}
// set lock
dir.locked = 1;
if (!prev.locked) {
change = true;
}
// has leaf root to `dirs: 1`
dir.dirs = 1;
if (!prev.dirs) {
change = true;
}
// set ts
$.each(self.leafRoots[dir.hash], function() {
var f = self.file(this);
if (f && f.ts && (dir.ts || 0) < f.ts) {
dir.ts = f.ts;
}
});
if (prevTs !== dir.ts) {
change = true;
}
return change;
},
/**
* To aborted XHR object
*
* @param Object xhr
* @param Object opts
*
* @return void
*/
abortXHR : function(xhr, o) {
var opts = o || {};
if (xhr) {
opts.quiet && (xhr.quiet = true);
if (opts.abort && xhr._requestId) {
this.request({
data: {
cmd: 'abort',
id: xhr._requestId
},
preventDefault: true
});
}
xhr.abort();
xhr = void 0;
}
},
/**
* Gets the request identifier
*
* @return String The request identifier.
*/
getRequestId : function() {
return (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16);
},
/**
* Flip key and value of array or object
*
* @param Array | Object { a: 1, b: 1, c: 2 }
* @param Mixed Static value
* @return Object { 1: "b", 2: "c" }
*/
arrayFlip : function (trans, val) {
var key,
tmpArr = {},
isArr = $.isArray(trans);
for (key in trans) {
if (isArr || trans.hasOwnProperty(key)) {
tmpArr[trans[key]] = val || key;
}
}
return tmpArr;
},
/**
* Return array ["name without extention", "extention"]
*
* @param String name
*
* @return Array
*
*/
splitFileExtention : function(name) {
var m;
if (m = name.match(/^(.+?)?\.((?:tar\.(?:gz|bz|bz2|z|lzo))|cpio\.gz|ps\.gz|xcf\.(?:gz|bz2)|[a-z0-9]{1,10})$/i)) {
if (typeof m[1] === 'undefined') {
m[1] = '';
}
return [m[1], m[2]];
} else {
return [name, ''];
}
},
/**
* Slice the ArrayBuffer by sliceSize
*
* @param arraybuffer arrayBuffer The array buffer
* @param Number sliceSize The slice size
* @return Array Array of sleced arraybuffer
*/
sliceArrayBuffer : function(arrayBuffer, sliceSize) {
var segments= [],
fi = 0;
while(fi * sliceSize < arrayBuffer.byteLength){
segments.push(arrayBuffer.slice(fi * sliceSize, (fi + 1) * sliceSize));
fi++;
}
return segments;
},
arrayBufferToBase64 : function(ab) {
if (!window.btoa) {
return '';
}
var dView = new Uint8Array(ab), // Get a byte view
arr = Array.prototype.slice.call(dView), // Create a normal array
arr1 = arr.map(function(item) {
return String.fromCharCode(item); // Convert
});
return window.btoa(arr1.join('')); // Form a string
},
log : function(m) { window.console && window.console.log && window.console.log(m); return this; },
debug : function(type, m) {
var d = this.options.debug;
if (d && (d === 'all' || d[type])) {
window.console && window.console.log && window.console.log('elfinder debug: ['+type+'] ['+this.id+']', m);
}
if (type === 'backend-error') {
if (! this.cwd().hash || (d && (d === 'all' || d['backend-error']))) {
m = Array.isArray(m)? m : [ m ];
this.error(m);
}
} else if (type === 'backend-debug') {
this.trigger('backenddebug', m);
}
return this;
},
time : function(l) { window.console && window.console.time && window.console.time(l); },
timeEnd : function(l) { window.console && window.console.timeEnd && window.console.timeEnd(l); }
};
/**
* for conpat ex. ie8...
*
* Object.keys() - JavaScript | MDN
* https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
*/
if (!Object.keys) {
Object.keys = (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function (obj) {
if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
var result = [];
for (var prop in obj) {
if (hasOwnProperty.call(obj, prop)) result.push(prop);
}
if (hasDontEnumBug) {
for (var i=0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
}
}
return result;
};
})();
}
// Array.isArray
if (!Array.isArray) {
Array.isArray = function(arr) {
return jQuery.isArray(arr);
};
}
// Object.assign
if (!Object.assign) {
Object.assign = function() {
return jQuery.extend.apply(null, arguments);
};
}
// String.repeat
if (!String.prototype.repeat) {
String.prototype.repeat = function(count) {
'use strict';
if (this == null) {
throw new TypeError('can\'t convert ' + this + ' to object');
}
var str = '' + this;
count = +count;
if (count != count) {
count = 0;
}
if (count < 0) {
throw new RangeError('repeat count must be non-negative');
}
if (count == Infinity) {
throw new RangeError('repeat count must be less than infinity');
}
count = Math.floor(count);
if (str.length == 0 || count == 0) {
return '';
}
// Ensuring count is a 31-bit integer allows us to heavily optimize the
// main part. But anyway, most current (August 2014) browsers can't handle
// strings 1 << 28 chars or longer, so:
if (str.length * count >= 1 << 28) {
throw new RangeError('repeat count must not overflow maximum string size');
}
var rpt = '';
for (var i = 0; i < count; i++) {
rpt += str;
}
return rpt;
};
}
// String.trim
if (!String.prototype.trim) {
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, '');
};
}
// Array.apply
(function () {
try {
Array.apply(null, {});
return;
} catch (e) { }
var toString = Object.prototype.toString,
arrayType = '[object Array]',
_apply = Function.prototype.apply,
slice = /*@cc_on @if (@_jscript_version <= 5.8)
function () {
var a = [], i = this.length;
while (i-- > 0) a[i] = this[i];
return a;
}@else@*/Array.prototype.slice/*@end@*/;
Function.prototype.apply = function apply(thisArg, argArray) {
return _apply.call(this, thisArg,
toString.call(argArray) === arrayType ? argArray : slice.call(argArray));
};
})();
// Array.from
if (!Array.from) {
Array.from = function(obj) {
return obj.length === 1 ? [obj[0]] : Array.apply(null, obj);
};
}
// window.requestAnimationFrame and window.cancelAnimationFrame
if (!window.cancelAnimationFrame) {
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
// MIT license
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
|| window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
}
/*
* File: /js/elFinder.version.js
*/
/**
* Application version
*
* @type String
**/
elFinder.prototype.version = '2.1.43';
/*
* File: /js/jquery.elfinder.js
*/
/*** jQuery UI droppable performance tune for elFinder ***/
(function(){
if ($.ui) {
if ($.ui.ddmanager) {
var origin = $.ui.ddmanager.prepareOffsets;
$.ui.ddmanager.prepareOffsets = function( t, event ) {
var isOutView = function(elem) {
if (elem.is(':hidden')) {
return true;
}
var rect = elem[0].getBoundingClientRect();
return document.elementFromPoint(rect.left, rect.top)? false : true;
};
if (event.type === 'mousedown' || t.options.elfRefresh) {
var i, d,
m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
l = m.length;
for ( i = 0; i < l; i++ ) {
d = m[ i ];
if (d.options.autoDisable && (!d.options.disabled || d.options.autoDisable > 1)) {
d.options.disabled = isOutView(d.element);
d.options.autoDisable = d.options.disabled? 2 : 1;
}
}
}
// call origin function
return origin( t, event );
};
}
}
})();
/**
*
* jquery.binarytransport.js
*
* @description. jQuery ajax transport for making binary data type requests.
* @version 1.0
* @author Henry Algus <henryalgus@gmail.com>
*
*/
// use this transport for "binary" data type
$.ajaxTransport('+binary', function(options, originalOptions, jqXHR) {
// check for conditions and support for blob / arraybuffer response type
if (window.FormData && ((options.dataType && (options.dataType == 'binary')) || (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) || (window.Blob && options.data instanceof Blob)))))
{
var xhr;
return {
// create new XMLHttpRequest
send: function(headers, callback){
// setup all variables
xhr = new XMLHttpRequest();
var url = options.url,
type = options.type,
async = options.async || true,
// blob or arraybuffer. Default is blob
dataType = options.responseType || 'blob',
data = options.data || null,
username = options.username,
password = options.password;
xhr.addEventListener('load', function(){
var data = {};
data[options.dataType] = xhr.response;
// make callback and send data
callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders());
});
xhr.open(type, url, async, username, password);
// setup custom headers
for (var i in headers ) {
xhr.setRequestHeader(i, headers[i] );
}
// setuo xhrFields
if (options.xhrFields) {
for (var key in options.xhrFields) {
if (key in xhr) {
xhr[key] = options.xhrFields[key];
}
}
}
xhr.responseType = dataType;
xhr.send(data);
},
abort: function(){
xhr.abort();
}
};
}
});
/*!
* jQuery UI Touch Punch 0.2.3
*
* Copyright 20112014, Dave Furfero
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* Depends:
* jquery.ui.widget.js
* jquery.ui.mouse.js
*/
(function ($) {
// Detect touch support
$.support.touch = 'ontouchend' in document;
// Ignore browsers without touch support
if (!$.support.touch) {
return;
}
var mouseProto = $.ui.mouse.prototype,
_mouseInit = mouseProto._mouseInit,
_mouseDestroy = mouseProto._mouseDestroy,
touchHandled,
posX, posY;
/**
* Simulate a mouse event based on a corresponding touch event
* @param {Object} event A touch event
* @param {String} simulatedType The corresponding mouse event
*/
function simulateMouseEvent (event, simulatedType) {
// Ignore multi-touch events
if (event.originalEvent.touches.length > 1) {
return;
}
if (! $(event.currentTarget).hasClass('touch-punch-keep-default')) {
event.preventDefault();
}
var touch = event.originalEvent.changedTouches[0],
simulatedEvent = document.createEvent('MouseEvents');
// Initialize the simulated mouse event using the touch event's coordinates
simulatedEvent.initMouseEvent(
simulatedType, // type
true, // bubbles
true, // cancelable
window, // view
1, // detail
touch.screenX, // screenX
touch.screenY, // screenY
touch.clientX, // clientX
touch.clientY, // clientY
false, // ctrlKey
false, // altKey
false, // shiftKey
false, // metaKey
0, // button
null // relatedTarget
);
// Dispatch the simulated event to the target element
event.target.dispatchEvent(simulatedEvent);
}
/**
* Handle the jQuery UI widget's touchstart events
* @param {Object} event The widget element's touchstart event
*/
mouseProto._touchStart = function (event) {
var self = this;
// Ignore the event if another widget is already being handled
if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) {
return;
}
// Track element position to avoid "false" move
posX = event.originalEvent.changedTouches[0].screenX.toFixed(0);
posY = event.originalEvent.changedTouches[0].screenY.toFixed(0);
// Set the flag to prevent other widgets from inheriting the touch event
touchHandled = true;
// Track movement to determine if interaction was a click
self._touchMoved = false;
// Simulate the mouseover event
simulateMouseEvent(event, 'mouseover');
// Simulate the mousemove event
simulateMouseEvent(event, 'mousemove');
// Simulate the mousedown event
simulateMouseEvent(event, 'mousedown');
};
/**
* Handle the jQuery UI widget's touchmove events
* @param {Object} event The document's touchmove event
*/
mouseProto._touchMove = function (event) {
// Ignore event if not handled
if (!touchHandled) {
return;
}
// Ignore if it's a "false" move (position not changed)
var x = event.originalEvent.changedTouches[0].screenX.toFixed(0);
var y = event.originalEvent.changedTouches[0].screenY.toFixed(0);
// Ignore if it's a "false" move (position not changed)
if (Math.abs(posX - x) <= 4 && Math.abs(posY - y) <= 4) {
return;
}
// Interaction was not a click
this._touchMoved = true;
// Simulate the mousemove event
simulateMouseEvent(event, 'mousemove');
};
/**
* Handle the jQuery UI widget's touchend events
* @param {Object} event The document's touchend event
*/
mouseProto._touchEnd = function (event) {
// Ignore event if not handled
if (!touchHandled) {
return;
}
// Simulate the mouseup event
simulateMouseEvent(event, 'mouseup');
// Simulate the mouseout event
simulateMouseEvent(event, 'mouseout');
// If the touch interaction did not move, it should trigger a click
if (!this._touchMoved) {
// Simulate the click event
simulateMouseEvent(event, 'click');
}
// Unset the flag to allow other widgets to inherit the touch event
touchHandled = false;
this._touchMoved = false;
};
/**
* A duck punch of the $.ui.mouse _mouseInit method to support touch events.
* This method extends the widget with bound touch event handlers that
* translate touch events to mouse events and pass them to the widget's
* original mouse event handling methods.
*/
mouseProto._mouseInit = function () {
var self = this;
if (self.element.hasClass('touch-punch')) {
// Delegate the touch handlers to the widget's element
self.element.on({
touchstart: $.proxy(self, '_touchStart'),
touchmove: $.proxy(self, '_touchMove'),
touchend: $.proxy(self, '_touchEnd')
});
}
// Call the original $.ui.mouse init method
_mouseInit.call(self);
};
/**
* Remove the touch event handlers
*/
mouseProto._mouseDestroy = function () {
var self = this;
if (self.element.hasClass('touch-punch')) {
// Delegate the touch handlers to the widget's element
self.element.off({
touchstart: $.proxy(self, '_touchStart'),
touchmove: $.proxy(self, '_touchMove'),
touchend: $.proxy(self, '_touchEnd')
});
}
// Call the original $.ui.mouse destroy method
_mouseDestroy.call(self);
};
})(jQuery);
$.fn.elfinder = function(o, o2) {
if (o === 'instance') {
return this.getElFinder();
}
return this.each(function() {
var cmd = typeof o === 'string' ? o : '',
bootCallback = typeof o2 === 'function'? o2 : void(0),
opts;
if (!this.elfinder) {
if ($.isPlainObject(o)) {
new elFinder(this, o, bootCallback);
}
} else {
switch(cmd) {
case 'close':
case 'hide':
this.elfinder.hide();
break;
case 'open':
case 'show':
this.elfinder.show();
break;
case 'destroy':
this.elfinder.destroy();
break;
case 'reload':
case 'restart':
if (this.elfinder) {
opts = this.elfinder.options;
bootCallback = this.elfinder.bootCallback;
this.elfinder.destroy();
new elFinder(this, $.extend(true, opts, $.isPlainObject(o2)? o2 : {}), bootCallback);
}
break;
}
}
});
};
$.fn.getElFinder = function() {
var instance;
this.each(function() {
if (this.elfinder) {
instance = this.elfinder;
return false;
}
});
return instance;
};
$.fn.elfUiWidgetInstance = function(name) {
try {
return this[name]('instance');
} catch(e) {
// fallback for jQuery UI < 1.11
var data = this.data('ui-' + name);
if (data && typeof data === 'object' && data.widgetFullName === 'ui-' + name) {
return data;
}
return null;
}
};
// function scrollRight
if (! $.fn.scrollRight) {
$.fn.extend({
scrollRight: function (val) {
var node = this.get(0);
if (val === undefined) {
return Math.max(0, node.scrollWidth - (node.scrollLeft + node.clientWidth));
}
return this.scrollLeft(node.scrollWidth - node.clientWidth - val);
}
});
}
// function scrollBottom
if (! $.fn.scrollBottom) {
$.fn.extend({
scrollBottom: function(val) {
var node = this.get(0);
if (val === undefined) {
return Math.max(0, node.scrollHeight - (node.scrollTop + node.clientHeight));
}
return this.scrollTop(node.scrollHeight - node.clientHeight - val);
}
});
}
/*
* File: /js/elFinder.mimetypes.js
*/
elFinder.prototype.mimeTypes = {"application\/x-executable":"exe","application\/x-jar":"jar","application\/x-gzip":"gz","application\/x-bzip2":"tbz","application\/x-rar":"rar","text\/x-php":"php","text\/javascript":"js","application\/rtfd":"rtfd","text\/x-python":"py","text\/x-ruby":"rb","text\/x-shellscript":"sh","text\/x-perl":"pl","text\/xml":"xml","text\/x-csrc":"c","text\/x-chdr":"h","text\/x-c++src":"cpp","text\/x-c++hdr":"hh","text\/x-markdown":"md","text\/x-yaml":"yml","image\/x-ms-bmp":"bmp","image\/x-targa":"tga","image\/xbm":"xbm","image\/pxm":"pxm","audio\/wav":"wav","video\/x-dv":"dv","video\/x-ms-wmv":"wm","video\/ogg":"ogm","video\/MP2T":"m2ts","application\/x-mpegURL":"m3u8","application\/dash+xml":"mpd","application\/andrew-inset":"ez","application\/applixware":"aw","application\/atom+xml":"atom","application\/atomcat+xml":"atomcat","application\/atomsvc+xml":"atomsvc","application\/ccxml+xml":"ccxml","application\/cdmi-capability":"cdmia","application\/cdmi-container":"cdmic","application\/cdmi-domain":"cdmid","application\/cdmi-object":"cdmio","application\/cdmi-queue":"cdmiq","application\/cu-seeme":"cu","application\/davmount+xml":"davmount","application\/docbook+xml":"dbk","application\/dssc+der":"dssc","application\/dssc+xml":"xdssc","application\/ecmascript":"ecma","application\/emma+xml":"emma","application\/epub+zip":"epub","application\/exi":"exi","application\/font-tdpfr":"pfr","application\/gml+xml":"gml","application\/gpx+xml":"gpx","application\/gxf":"gxf","application\/hyperstudio":"stk","application\/inkml+xml":"ink","application\/ipfix":"ipfix","application\/java-serialized-object":"ser","application\/java-vm":"class","application\/json":"json","application\/jsonml+json":"jsonml","application\/lost+xml":"lostxml","application\/mac-binhex40":"hqx","application\/mac-compactpro":"cpt","application\/mads+xml":"mads","application\/marc":"mrc","application\/marcxml+xml":"mrcx","application\/mathematica":"ma","application\/mathml+xml":"mathml","application\/mbox":"mbox","application\/mediaservercontrol+xml":"mscml","application\/metalink+xml":"metalink","application\/metalink4+xml":"meta4","application\/mets+xml":"mets","application\/mods+xml":"mods","application\/mp21":"m21","application\/mp4":"mp4s","application\/msword":"doc","application\/mxf":"mxf","application\/octet-stream":"bin","application\/oda":"oda","application\/oebps-package+xml":"opf","application\/ogg":"ogx","application\/omdoc+xml":"omdoc","application\/onenote":"onetoc","application\/oxps":"oxps","application\/patch-ops-error+xml":"xer","application\/pdf":"pdf","application\/pgp-encrypted":"pgp","application\/pgp-signature":"asc","application\/pics-rules":"prf","application\/pkcs10":"p10","application\/pkcs7-mime":"p7m","application\/pkcs7-signature":"p7s","application\/pkcs8":"p8","application\/pkix-attr-cert":"ac","application\/pkix-cert":"cer","application\/pkix-crl":"crl","application\/pkix-pkipath":"pkipath","application\/pkixcmp":"pki","application\/pls+xml":"pls","application\/postscript":"ai","application\/prs.cww":"cww","application\/pskc+xml":"pskcxml","application\/rdf+xml":"rdf","application\/reginfo+xml":"rif","application\/relax-ng-compact-syntax":"rnc","application\/resource-lists+xml":"rl","application\/resource-lists-diff+xml":"rld","application\/rls-services+xml":"rs","application\/rpki-ghostbusters":"gbr","application\/rpki-manifest":"mft","application\/rpki-roa":"roa","application\/rsd+xml":"rsd","application\/rss+xml":"rss","application\/rtf":"rtf","application\/sbml+xml":"sbml","application\/scvp-cv-request":"scq","application\/scvp-cv-response":"scs","application\/scvp-vp-request":"spq","application\/scvp-vp-response":"spp","application\/sdp":"sdp","application\/set-payment-initiation":"setpay","application\/set-registration-initiation":"setreg","application\/shf+xml":"shf","application\/smil+xml":"smi","application\/sparql-query":"rq","application\/sparql-results+xml":"srx","application\/srgs":"gram","application\/srgs+xml":"grxml","application\/sru+xml":"sru","application\/ssdl+xml":"ssdl","application\/ssml+xml":"ssml","application\/tei+xml":"tei","application\/thraud+xml":"tfi","application\/timestamped-data":"tsd","application\/vnd.3gpp.pic-bw-large":"plb","application\/vnd.3gpp.pic-bw-small":"psb","application\/vnd.3gpp.pic-bw-var":"pvb","application\/vnd.3gpp2.tcap":"tcap","application\/vnd.3m.post-it-notes":"pwn","application\/vnd.accpac.simply.aso":"aso","application\/vnd.accpac.simply.imp":"imp","application\/vnd.acucobol":"acu","application\/vnd.acucorp":"atc","application\/vnd.adobe.air-application-installer-package+zip":"air","application\/vnd.adobe.formscentral.fcdt":"fcdt","application\/vnd.adobe.fxp":"fxp","application\/vnd.adobe.xdp+xml":"xdp","application\/vnd.adobe.xfdf":"xfdf","application\/vnd.ahead.space":"ahead","application\/vnd.airzip.filesecure.azf":"azf","application\/vnd.airzip.filesecure.azs":"azs","application\/vnd.amazon.ebook":"azw","application\/vnd.americandynamics.acc":"acc","application\/vnd.amiga.ami":"ami","application\/vnd.android.package-archive":"apk","application\/vnd.anser-web-certificate-issue-initiation":"cii","application\/vnd.anser-web-funds-transfer-initiation":"fti","application\/vnd.antix.game-component":"atx","application\/vnd.apple.installer+xml":"mpkg","application\/vnd.aristanetworks.swi":"swi","application\/vnd.astraea-software.iota":"iota","application\/vnd.audiograph":"aep","application\/vnd.blueice.multipass":"mpm","application\/vnd.bmi":"bmi","application\/vnd.businessobjects":"rep","application\/vnd.chemdraw+xml":"cdxml","application\/vnd.chipnuts.karaoke-mmd":"mmd","application\/vnd.cinderella":"cdy","application\/vnd.claymore":"cla","application\/vnd.cloanto.rp9":"rp9","application\/vnd.clonk.c4group":"c4g","application\/vnd.cluetrust.cartomobile-config":"c11amc","application\/vnd.cluetrust.cartomobile-config-pkg":"c11amz","application\/vnd.commonspace":"csp","application\/vnd.contact.cmsg":"cdbcmsg","application\/vnd.cosmocaller":"cmc","application\/vnd.crick.clicker":"clkx","application\/vnd.crick.clicker.keyboard":"clkk","application\/vnd.crick.clicker.palette":"clkp","application\/vnd.crick.clicker.template":"clkt","application\/vnd.crick.clicker.wordbank":"clkw","application\/vnd.criticaltools.wbs+xml":"wbs","application\/vnd.ctc-posml":"pml","application\/vnd.cups-ppd":"ppd","application\/vnd.curl.car":"car","application\/vnd.curl.pcurl":"pcurl","application\/vnd.dart":"dart","application\/vnd.data-vision.rdz":"rdz","application\/vnd.dece.data":"uvf","application\/vnd.dece.ttml+xml":"uvt","application\/vnd.dece.unspecified":"uvx","application\/vnd.dece.zip":"uvz","application\/vnd.denovo.fcselayout-link":"fe_launch","application\/vnd.dna":"dna","application\/vnd.dolby.mlp":"mlp","application\/vnd.dpgraph":"dpg","application\/vnd.dreamfactory":"dfac","application\/vnd.ds-keypoint":"kpxx","application\/vnd.dvb.ait":"ait","application\/vnd.dvb.service":"svc","application\/vnd.dynageo":"geo","application\/vnd.ecowin.chart":"mag","application\/vnd.enliven":"nml","application\/vnd.epson.esf":"esf","application\/vnd.epson.msf":"msf","application\/vnd.epson.quickanime":"qam","application\/vnd.epson.salt":"slt","application\/vnd.epson.ssf":"ssf","application\/vnd.eszigno3+xml":"es3","application\/vnd.ezpix-album":"ez2","application\/vnd.ezpix-package":"ez3","application\/vnd.fdf":"fdf","application\/vnd.fdsn.mseed":"mseed","application\/vnd.fdsn.seed":"seed","application\/vnd.flographit":"gph","application\/vnd.fluxtime.clip":"ftc","application\/vnd.framemaker":"fm","application\/vnd.frogans.fnc":"fnc","application\/vnd.frogans.ltf":"ltf","application\/vnd.fsc.weblaunch":"fsc","application\/vnd.fujitsu.oasys":"oas","application\/vnd.fujitsu.oasys2":"oa2","application\/vnd.fujitsu.oasys3":"oa3","application\/vnd.fujitsu.oasysgp":"fg5","application\/vnd.fujitsu.oasysprs":"bh2","application\/vnd.fujixerox.ddd":"ddd","application\/vnd.fujixerox.docuworks":"xdw","application\/vnd.fujixerox.docuworks.binder":"xbd","application\/vnd.fuzzysheet":"fzs","application\/vnd.genomatix.tuxedo":"txd","application\/vnd.geogebra.file":"ggb","application\/vnd.geogebra.tool":"ggt","application\/vnd.geometry-explorer":"gex","application\/vnd.geonext":"gxt","application\/vnd.geoplan":"g2w","application\/vnd.geospace":"g3w","application\/vnd.gmx":"gmx","application\/vnd.google-earth.kml+xml":"kml","application\/vnd.google-earth.kmz":"kmz","application\/vnd.grafeq":"gqf","application\/vnd.groove-account":"gac","application\/vnd.groove-help":"ghf","application\/vnd.groove-identity-message":"gim","application\/vnd.groove-injector":"grv","application\/vnd.groove-tool-message":"gtm","application\/vnd.groove-tool-template":"tpl","application\/vnd.groove-vcard":"vcg","application\/vnd.hal+xml":"hal","application\/vnd.handheld-entertainment+xml":"zmm","application\/vnd.hbci":"hbci","application\/vnd.hhe.lesson-player":"les","application\/vnd.hp-hpgl":"hpgl","application\/vnd.hp-hpid":"hpid","application\/vnd.hp-hps":"hps","application\/vnd.hp-jlyt":"jlt","application\/vnd.hp-pcl":"pcl","application\/vnd.hp-pclxl":"pclxl","application\/vnd.hydrostatix.sof-data":"sfd-hdstx","application\/vnd.ibm.minipay":"mpy","application\/vnd.ibm.modcap":"afp","application\/vnd.ibm.rights-management":"irm","application\/vnd.ibm.secure-container":"sc","application\/vnd.iccprofile":"icc","application\/vnd.igloader":"igl","application\/vnd.immervision-ivp":"ivp","application\/vnd.immervision-ivu":"ivu","application\/vnd.insors.igm":"igm","application\/vnd.intercon.formnet":"xpw","application\/vnd.intergeo":"i2g","application\/vnd.intu.qbo":"qbo","application\/vnd.intu.qfx":"qfx","application\/vnd.ipunplugged.rcprofile":"rcprofile","application\/vnd.irepository.package+xml":"irp","application\/vnd.is-xpr":"xpr","application\/vnd.isac.fcs":"fcs","application\/vnd.jam":"jam","application\/vnd.jcp.javame.midlet-rms":"rms","application\/vnd.jisp":"jisp","application\/vnd.joost.joda-archive":"joda","application\/vnd.kahootz":"ktz","application\/vnd.kde.karbon":"karbon","application\/vnd.kde.kchart":"chrt","application\/vnd.kde.kformula":"kfo","application\/vnd.kde.kivio":"flw","application\/vnd.kde.kontour":"kon","application\/vnd.kde.kpresenter":"kpr","application\/vnd.kde.kspread":"ksp","application\/vnd.kde.kword":"kwd","application\/vnd.kenameaapp":"htke","application\/vnd.kidspiration":"kia","application\/vnd.kinar":"kne","application\/vnd.koan":"skp","application\/vnd.kodak-descriptor":"sse","application\/vnd.las.las+xml":"lasxml","application\/vnd.llamagraphics.life-balance.desktop":"lbd","application\/vnd.llamagraphics.life-balance.exchange+xml":"lbe","application\/vnd.lotus-1-2-3":123,"application\/vnd.lotus-approach":"apr","application\/vnd.lotus-freelance":"pre","application\/vnd.lotus-notes":"nsf","application\/vnd.lotus-organizer":"org","application\/vnd.lotus-screencam":"scm","application\/vnd.lotus-wordpro":"lwp","application\/vnd.macports.portpkg":"portpkg","application\/vnd.mcd":"mcd","application\/vnd.medcalcdata":"mc1","application\/vnd.mediastation.cdkey":"cdkey","application\/vnd.mfer":"mwf","application\/vnd.mfmp":"mfm","application\/vnd.micrografx.flo":"flo","application\/vnd.micrografx.igx":"igx","application\/vnd.mif":"mif","application\/vnd.mobius.daf":"daf","application\/vnd.mobius.dis":"dis","application\/vnd.mobius.mbk":"mbk","application\/vnd.mobius.mqy":"mqy","application\/vnd.mobius.msl":"msl","application\/vnd.mobius.plc":"plc","application\/vnd.mobius.txf":"txf","application\/vnd.mophun.application":"mpn","application\/vnd.mophun.certificate":"mpc","application\/vnd.mozilla.xul+xml":"xul","application\/vnd.ms-artgalry":"cil","application\/vnd.ms-cab-compressed":"cab","application\/vnd.ms-excel":"xls","application\/vnd.ms-excel.addin.macroenabled.12":"xlam","application\/vnd.ms-excel.sheet.binary.macroenabled.12":"xlsb","application\/vnd.ms-excel.sheet.macroenabled.12":"xlsm","application\/vnd.ms-excel.template.macroenabled.12":"xltm","application\/vnd.ms-fontobject":"eot","application\/vnd.ms-htmlhelp":"chm","application\/vnd.ms-ims":"ims","application\/vnd.ms-lrm":"lrm","application\/vnd.ms-officetheme":"thmx","application\/vnd.ms-pki.seccat":"cat","application\/vnd.ms-pki.stl":"stl","application\/vnd.ms-powerpoint":"ppt","application\/vnd.ms-powerpoint.addin.macroenabled.12":"ppam","application\/vnd.ms-powerpoint.presentation.macroenabled.12":"pptm","application\/vnd.ms-powerpoint.slide.macroenabled.12":"sldm","application\/vnd.ms-powerpoint.slideshow.macroenabled.12":"ppsm","application\/vnd.ms-powerpoint.template.macroenabled.12":"potm","application\/vnd.ms-project":"mpp","application\/vnd.ms-word.document.macroenabled.12":"docm","application\/vnd.ms-word.template.macroenabled.12":"dotm","application\/vnd.ms-works":"wps","application\/vnd.ms-wpl":"wpl","application\/vnd.ms-xpsdocument":"xps","application\/vnd.mseq":"mseq","application\/vnd.musician":"mus","application\/vnd.muvee.style":"msty","application\/vnd.mynfc":"taglet","application\/vnd.neurolanguage.nlu":"nlu","application\/vnd.nitf":"ntf","application\/vnd.noblenet-directory":"nnd","application\/vnd.noblenet-sealer":"nns","application\/vnd.noblenet-web":"nnw","application\/vnd.nokia.n-gage.data":"ngdat","application\/vnd.nokia.n-gage.symbian.install":"n-gage","application\/vnd.nokia.radio-preset":"rpst","application\/vnd.nokia.radio-presets":"rpss","application\/vnd.novadigm.edm":"edm","application\/vnd.novadigm.edx":"edx","application\/vnd.novadigm.ext":"ext","application\/vnd.oasis.opendocument.chart":"odc","application\/vnd.oasis.opendocument.chart-template":"otc","application\/vnd.oasis.opendocument.database":"odb","application\/vnd.oasis.opendocument.formula":"odf","application\/vnd.oasis.opendocument.formula-template":"odft","application\/vnd.oasis.opendocument.graphics":"odg","application\/vnd.oasis.opendocument.graphics-template":"otg","application\/vnd.oasis.opendocument.image":"odi","application\/vnd.oasis.opendocument.image-template":"oti","application\/vnd.oasis.opendocument.presentation":"odp","application\/vnd.oasis.opendocument.presentation-template":"otp","application\/vnd.oasis.opendocument.spreadsheet":"ods","application\/vnd.oasis.opendocument.spreadsheet-template":"ots","application\/vnd.oasis.opendocument.text":"odt","application\/vnd.oasis.opendocument.text-master":"odm","application\/vnd.oasis.opendocument.text-template":"ott","application\/vnd.oasis.opendocument.text-web":"oth","application\/vnd.olpc-sugar":"xo","application\/vnd.oma.dd2+xml":"dd2","application\/vnd.openofficeorg.extension":"oxt","application\/vnd.openxmlformats-officedocument.presentationml.presentation":"pptx","application\/vnd.openxmlformats-officedocument.presentationml.slide":"sldx","application\/vnd.openxmlformats-officedocument.presentationml.slideshow":"ppsx","application\/vnd.openxmlformats-officedocument.presentationml.template":"potx","application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet":"xlsx","application\/vnd.openxmlformats-officedocument.spreadsheetml.template":"xltx","application\/vnd.openxmlformats-officedocument.wordprocessingml.document":"docx","application\/vnd.openxmlformats-officedocument.wordprocessingml.template":"dotx","application\/vnd.osgeo.mapguide.package":"mgp","application\/vnd.osgi.dp":"dp","application\/vnd.osgi.subsystem":"esa","application\/vnd.palm":"pdb","application\/vnd.pawaafile":"paw","application\/vnd.pg.format":"str","application\/vnd.pg.osasli":"ei6","application\/vnd.picsel":"efif","application\/vnd.pmi.widget":"wg","application\/vnd.pocketlearn":"plf","application\/vnd.powerbuilder6":"pbd","application\/vnd.previewsystems.box":"box","application\/vnd.proteus.magazine":"mgz","application\/vnd.publishare-delta-tree":"qps","application\/vnd.pvi.ptid1":"ptid","application\/vnd.quark.quarkxpress":"qxd","application\/vnd.realvnc.bed":"bed","application\/vnd.recordare.musicxml":"mxl","application\/vnd.recordare.musicxml+xml":"musicxml","application\/vnd.rig.cryptonote":"cryptonote","application\/vnd.rim.cod":"cod","application\/vnd.rn-realmedia":"rm","application\/vnd.rn-realmedia-vbr":"rmvb","application\/vnd.route66.link66+xml":"link66","application\/vnd.sailingtracker.track":"st","application\/vnd.seemail":"see","application\/vnd.sema":"sema","application\/vnd.semd":"semd","application\/vnd.semf":"semf","application\/vnd.shana.informed.formdata":"ifm","application\/vnd.shana.informed.formtemplate":"itp","application\/vnd.shana.informed.interchange":"iif","application\/vnd.shana.informed.package":"ipk","application\/vnd.simtech-mindmapper":"twd","application\/vnd.smaf":"mmf","application\/vnd.smart.teacher":"teacher","application\/vnd.solent.sdkm+xml":"sdkm","application\/vnd.spotfire.dxp":"dxp","application\/vnd.spotfire.sfs":"sfs","application\/vnd.stardivision.calc":"sdc","application\/vnd.stardivision.draw":"sda","application\/vnd.stardivision.impress":"sdd","application\/vnd.stardivision.math":"smf","application\/vnd.stardivision.writer":"sdw","application\/vnd.stardivision.writer-global":"sgl","application\/vnd.stepmania.package":"smzip","application\/vnd.stepmania.stepchart":"sm","application\/vnd.sun.xml.calc":"sxc","application\/vnd.sun.xml.calc.template":"stc","application\/vnd.sun.xml.draw":"sxd","application\/vnd.sun.xml.draw.template":"std","application\/vnd.sun.xml.impress":"sxi","application\/vnd.sun.xml.impress.template":"sti","application\/vnd.sun.xml.math":"sxm","application\/vnd.sun.xml.writer":"sxw","application\/vnd.sun.xml.writer.global":"sxg","application\/vnd.sun.xml.writer.template":"stw","application\/vnd.sus-calendar":"sus","application\/vnd.svd":"svd","application\/vnd.symbian.install":"sis","application\/vnd.syncml+xml":"xsm","application\/vnd.syncml.dm+wbxml":"bdm","application\/vnd.syncml.dm+xml":"xdm","application\/vnd.tao.intent-module-archive":"tao","application\/vnd.tcpdump.pcap":"pcap","application\/vnd.tmobile-livetv":"tmo","application\/vnd.trid.tpt":"tpt","application\/vnd.triscape.mxs":"mxs","application\/vnd.trueapp":"tra","application\/vnd.ufdl":"ufd","application\/vnd.uiq.theme":"utz","application\/vnd.umajin":"umj","application\/vnd.unity":"unityweb","application\/vnd.uoml+xml":"uoml","application\/vnd.vcx":"vcx","application\/vnd.visio":"vsd","application\/vnd.visionary":"vis","application\/vnd.vsf":"vsf","application\/vnd.wap.wbxml":"wbxml","application\/vnd.wap.wmlc":"wmlc","application\/vnd.wap.wmlscriptc":"wmlsc","application\/vnd.webturbo":"wtb","application\/vnd.wolfram.player":"nbp","application\/vnd.wordperfect":"wpd","application\/vnd.wqd":"wqd","application\/vnd.wt.stf":"stf","application\/vnd.xara":"xar","application\/vnd.xfdl":"xfdl","application\/vnd.yamaha.hv-dic":"hvd","application\/vnd.yamaha.hv-script":"hvs","application\/vnd.yamaha.hv-voice":"hvp","application\/vnd.yamaha.openscoreformat":"osf","application\/vnd.yamaha.openscoreformat.osfpvg+xml":"osfpvg","application\/vnd.yamaha.smaf-audio":"saf","application\/vnd.yamaha.smaf-phrase":"spf","application\/vnd.yellowriver-custom-menu":"cmp","application\/vnd.zul":"zir","application\/vnd.zzazz.deck+xml":"zaz","application\/voicexml+xml":"vxml","application\/widget":"wgt","application\/winhlp":"hlp","application\/wsdl+xml":"wsdl","application\/wspolicy+xml":"wspolicy","application\/x-7z-compressed":"7z","application\/x-abiword":"abw","application\/x-ace-compressed":"ace","application\/x-apple-diskimage":"dmg","application\/x-authorware-bin":"aab","application\/x-authorware-map":"aam","application\/x-authorware-seg":"aas","application\/x-bcpio":"bcpio","application\/x-bittorrent":"torrent","application\/x-blorb":"blb","application\/x-bzip":"bz","application\/x-cbr":"cbr","application\/x-cdlink":"vcd","application\/x-cfs-compressed":"cfs","application\/x-chat":"chat","application\/x-chess-pgn":"pgn","application\/x-conference":"nsc","application\/x-cpio":"cpio","application\/x-csh":"csh","application\/x-debian-package":"deb","application\/x-dgc-compressed":"dgc","application\/x-director":"dir","application\/x-doom":"wad","application\/x-dtbncx+xml":"ncx","application\/x-dtbook+xml":"dtb","application\/x-dtbresource+xml":"res","application\/x-dvi":"dvi","application\/x-envoy":"evy","application\/x-eva":"eva","application\/x-font-bdf":"bdf","application\/x-font-ghostscript":"gsf","application\/x-font-linux-psf":"psf","application\/x-font-pcf":"pcf","application\/x-font-snf":"snf","application\/x-font-type1":"pfa","application\/x-freearc":"arc","application\/x-futuresplash":"spl","application\/x-gca-compressed":"gca","application\/x-glulx":"ulx","application\/x-gnumeric":"gnumeric","application\/x-gramps-xml":"gramps","application\/x-gtar":"gtar","application\/x-hdf":"hdf","application\/x-install-instructions":"install","application\/x-iso9660-image":"iso","application\/x-java-jnlp-file":"jnlp","application\/x-latex":"latex","application\/x-lzh-compressed":"lzh","application\/x-mie":"mie","application\/x-mobipocket-ebook":"prc","application\/x-ms-application":"application","application\/x-ms-shortcut":"lnk","application\/x-ms-wmd":"wmd","application\/x-ms-wmz":"wmz","application\/x-ms-xbap":"xbap","application\/x-msaccess":"mdb","application\/x-msbinder":"obd","application\/x-mscardfile":"crd","application\/x-msclip":"clp","application\/x-msdownload":"dll","application\/x-msmediaview":"mvb","application\/x-msmetafile":"wmf","application\/x-msmoney":"mny","application\/x-mspublisher":"pub","application\/x-msschedule":"scd","application\/x-msterminal":"trm","application\/x-mswrite":"wri","application\/x-netcdf":"nc","application\/x-nzb":"nzb","application\/x-pkcs12":"p12","application\/x-pkcs7-certificates":"p7b","application\/x-pkcs7-certreqresp":"p7r","application\/x-research-info-systems":"ris","application\/x-shar":"shar","application\/x-shockwave-flash":"swf","application\/x-silverlight-app":"xap","application\/x-sql":"sql","application\/x-stuffit":"sit","application\/x-stuffitx":"sitx","application\/x-subrip":"srt","application\/x-sv4cpio":"sv4cpio","application\/x-sv4crc":"sv4crc","application\/x-t3vm-image":"t3","application\/x-tads":"gam","application\/x-tar":"tar","application\/x-tcl":"tcl","application\/x-tex":"tex","application\/x-tex-tfm":"tfm","application\/x-texinfo":"texinfo","application\/x-tgif":"obj","application\/x-ustar":"ustar","application\/x-wais-source":"src","application\/x-x509-ca-cert":"der","application\/x-xfig":"fig","application\/x-xliff+xml":"xlf","application\/x-xpinstall":"xpi","application\/x-xz":"xz","application\/x-zmachine":"z1","application\/xaml+xml":"xaml","application\/xcap-diff+xml":"xdf","application\/xenc+xml":"xenc","application\/xhtml+xml":"xhtml","application\/xml":"xsl","application\/xml-dtd":"dtd","application\/xop+xml":"xop","application\/xproc+xml":"xpl","application\/xslt+xml":"xslt","application\/xspf+xml":"xspf","application\/xv+xml":"mxml","application\/yang":"yang","application\/yin+xml":"yin","application\/zip":"zip","audio\/adpcm":"adp","audio\/basic":"au","audio\/midi":"mid","audio\/mp4":"m4a","audio\/mpeg":"mpga","audio\/ogg":"oga","audio\/s3m":"s3m","audio\/silk":"sil","audio\/vnd.dece.audio":"uva","audio\/vnd.digital-winds":"eol","audio\/vnd.dra":"dra","audio\/vnd.dts":"dts","audio\/vnd.dts.hd":"dtshd","audio\/vnd.lucent.voice":"lvp","audio\/vnd.ms-playready.media.pya":"pya","audio\/vnd.nuera.ecelp4800":"ecelp4800","audio\/vnd.nuera.ecelp7470":"ecelp7470","audio\/vnd.nuera.ecelp9600":"ecelp9600","audio\/vnd.rip":"rip","audio\/webm":"weba","audio\/x-aac":"aac","audio\/x-aiff":"aif","audio\/x-caf":"caf","audio\/x-flac":"flac","audio\/x-matroska":"mka","audio\/x-mpegurl":"m3u","audio\/x-ms-wax":"wax","audio\/x-ms-wma":"wma","audio\/x-pn-realaudio":"ram","audio\/x-pn-realaudio-plugin":"rmp","audio\/xm":"xm","chemical\/x-cdx":"cdx","chemical\/x-cif":"cif","chemical\/x-cmdf":"cmdf","chemical\/x-cml":"cml","chemical\/x-csml":"csml","chemical\/x-xyz":"xyz","font\/collection":"ttc","font\/otf":"otf","font\/ttf":"ttf","font\/woff":"woff","font\/woff2":"woff2","image\/cgm":"cgm","image\/g3fax":"g3","image\/gif":"gif","image\/ief":"ief","image\/jpeg":"jpeg","image\/ktx":"ktx","image\/png":"png","image\/prs.btif":"btif","image\/sgi":"sgi","image\/svg+xml":"svg","image\/tiff":"tiff","image\/vnd.adobe.photoshop":"psd","image\/vnd.dece.graphic":"uvi","image\/vnd.djvu":"djvu","image\/vnd.dvb.subtitle":"sub","image\/vnd.dwg":"dwg","image\/vnd.dxf":"dxf","image\/vnd.fastbidsheet":"fbs","image\/vnd.fpx":"fpx","image\/vnd.fst":"fst","image\/vnd.fujixerox.edmics-mmr":"mmr","image\/vnd.fujixerox.edmics-rlc":"rlc","image\/vnd.ms-modi":"mdi","image\/vnd.ms-photo":"wdp","image\/vnd.net-fpx":"npx","image\/vnd.wap.wbmp":"wbmp","image\/vnd.xiff":"xif","image\/webp":"webp","image\/x-3ds":"3ds","image\/x-cmu-raster":"ras","image\/x-cmx":"cmx","image\/x-freehand":"fh","image\/x-icon":"ico","image\/x-mrsid-image":"sid","image\/x-pcx":"pcx","image\/x-pict":"pic","image\/x-portable-anymap":"pnm","image\/x-portable-bitmap":"pbm","image\/x-portable-graymap":"pgm","image\/x-portable-pixmap":"ppm","image\/x-rgb":"rgb","image\/x-xpixmap":"xpm","image\/x-xwindowdump":"xwd","message\/rfc822":"eml","model\/iges":"igs","model\/mesh":"msh","model\/vnd.collada+xml":"dae","model\/vnd.dwf":"dwf","model\/vnd.gdl":"gdl","model\/vnd.gtw":"gtw","model\/vnd.vtu":"vtu","model\/vrml":"wrl","model\/x3d+binary":"x3db","model\/x3d+vrml":"x3dv","model\/x3d+xml":"x3d","text\/cache-manifest":"appcache","text\/calendar":"ics","text\/css":"css","text\/csv":"csv","text\/html":"html","text\/n3":"n3","text\/plain":"txt","text\/prs.lines.tag":"dsc","text\/richtext":"rtx","text\/sgml":"sgml","text\/tab-separated-values":"tsv","text\/troff":"t","text\/turtle":"ttl","text\/uri-list":"uri","text\/vcard":"vcard","text\/vnd.curl":"curl","text\/vnd.curl.dcurl":"dcurl","text\/vnd.curl.mcurl":"mcurl","text\/vnd.curl.scurl":"scurl","text\/vnd.fly":"fly","text\/vnd.fmi.flexstor":"flx","text\/vnd.graphviz":"gv","text\/vnd.in3d.3dml":"3dml","text\/vnd.in3d.spot":"spot","text\/vnd.sun.j2me.app-descriptor":"jad","text\/vnd.wap.wml":"wml","text\/vnd.wap.wmlscript":"wmls","text\/x-asm":"s","text\/x-c":"cc","text\/x-fortran":"f","text\/x-java-source":"java","text\/x-nfo":"nfo","text\/x-opml":"opml","text\/x-pascal":"p","text\/x-setext":"etx","text\/x-sfv":"sfv","text\/x-uuencode":"uu","text\/x-vcalendar":"vcs","text\/x-vcard":"vcf","video\/3gpp":"3gp","video\/3gpp2":"3g2","video\/h261":"h261","video\/h263":"h263","video\/h264":"h264","video\/jpeg":"jpgv","video\/jpm":"jpm","video\/mj2":"mj2","video\/mp4":"mp4","video\/mpeg":"mpeg","video\/quicktime":"qt","video\/vnd.dece.hd":"uvh","video\/vnd.dece.mobile":"uvm","video\/vnd.dece.pd":"uvp","video\/vnd.dece.sd":"uvs","video\/vnd.dece.video":"uvv","video\/vnd.dvb.file":"dvb","video\/vnd.fvt":"fvt","video\/vnd.mpegurl":"mxu","video\/vnd.ms-playready.media.pyv":"pyv","video\/vnd.uvvu.mp4":"uvu","video\/vnd.vivo":"viv","video\/webm":"webm","video\/x-f4v":"f4v","video\/x-fli":"fli","video\/x-flv":"flv","video\/x-m4v":"m4v","video\/x-matroska":"mkv","video\/x-mng":"mng","video\/x-ms-asf":"asf","video\/x-ms-vob":"vob","video\/x-ms-wmx":"wmx","video\/x-ms-wvx":"wvx","video\/x-msvideo":"avi","video\/x-sgi-movie":"movie","video\/x-smv":"smv","x-conference\/x-cooltalk":"ice","text\/x-sql":"sql","image\/x-pixlr-data":"pxd","image\/x-adobe-dng":"dng","image\/x-sketch":"sketch","image\/x-xcf":"xcf","audio\/amr":"amr","application\/plt":"plt","application\/sat":"sat","application\/step":"step","text\/x-httpd-cgi":"cgi","text\/x-asap":"asp","text\/x-jsp":"jsp"};
/*
* File: /js/elFinder.options.js
*/
/**
* Default elFinder config
*
* @type Object
* @autor Dmitry (dio) Levashov
*/
elFinder.prototype._options = {
/**
* URLs of 3rd party libraries CDN
*
* @type Object
*/
cdns : {
// for editor etc.
ace : 'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.1',
codemirror : 'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.40.2',
ckeditor : 'https://cdnjs.cloudflare.com/ajax/libs/ckeditor/4.10.0',
ckeditor5 : 'https://cdn.ckeditor.com/ckeditor5/11.1.1',
tinymce : 'https://cdnjs.cloudflare.com/ajax/libs/tinymce/4.8.3',
simplemde : 'https://cdnjs.cloudflare.com/ajax/libs/simplemde/1.11.2',
fabric16 : 'https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.7',
tui : 'https://uicdn.toast.com',
// for quicklook etc.
hls : 'https://cdnjs.cloudflare.com/ajax/libs/hls.js/0.10.1/hls.min.js',
dash : 'https://cdnjs.cloudflare.com/ajax/libs/dashjs/2.9.1/dash.all.min.js',
flv : 'https://cdnjs.cloudflare.com/ajax/libs/flv.js/1.4.2/flv.min.js',
prettify : 'https://cdn.jsdelivr.net/gh/google/code-prettify@453bd5f51e61245339b738b1bbdd42d7848722ba/loader/run_prettify.js',
psd : 'https://cdnjs.cloudflare.com/ajax/libs/psd.js/3.2.0/psd.min.js',
rar : 'https://cdn.jsdelivr.net/gh/nao-pon/rar.js@6cef13ec66dd67992fc7f3ea22f132d770ebaf8b/rar.min.js',
zlibUnzip : 'https://cdn.jsdelivr.net/gh/imaya/zlib.js@0.3.1/bin/unzip.min.js', // need check unzipFiles() in quicklook.plugins.js when update
zlibGunzip : 'https://cdn.jsdelivr.net/gh/imaya/zlib.js@0.3.1/bin/gunzip.min.js',
marked : 'https://cdnjs.cloudflare.com/ajax/libs/marked/0.5.1/marked.min.js',
sparkmd5 : 'https://cdnjs.cloudflare.com/ajax/libs/spark-md5/3.0.0/spark-md5.min.js',
jssha : 'https://cdnjs.cloudflare.com/ajax/libs/jsSHA/2.3.1/sha.js',
amr : 'https://cdn.jsdelivr.net/gh/yxl/opencore-amr-js@dcf3d2b5f384a1d9ded2a54e4c137a81747b222b/js/amrnb.js'
},
/**
* Connector url. Required!
*
* @type String
*/
url : '',
/**
* Ajax request type.
*
* @type String
* @default "get"
*/
requestType : 'get',
/**
* Use CORS to connector url
*
* @type Boolean|null true|false|null(Auto detect)
*/
cors : null,
/**
* Maximum number of concurrent connections on request
*
* @type Number
* @default 3
*/
requestMaxConn : 3,
/**
* Transport to send request to backend.
* Required for future extensions using websockets/webdav etc.
* Must be an object with "send" method.
* transport.send must return $.Deferred() object
*
* @type Object
* @default null
* @example
* transport : {
* init : function(elfinderInstance) { },
* send : function(options) {
* var dfrd = $.Deferred();
* // connect to backend ...
* return dfrd;
* },
* upload : function(data) {
* var dfrd = $.Deferred();
* // upload ...
* return dfrd;
* }
*
* }
**/
transport : {},
/**
* URL to upload file to.
* If not set - connector URL will be used
*
* @type String
* @default ''
*/
urlUpload : '',
/**
* Allow to drag and drop to upload files
*
* @type Boolean|String
* @default 'auto'
*/
dragUploadAllow : 'auto',
/**
* Confirmation dialog displayed at the time of overwriting upload
*
* @type Boolean
* @default true
*/
overwriteUploadConfirm : true,
/**
* Max size of chunked data of file upload
*
* @type Number
* @default 10485760(10MB)
*/
uploadMaxChunkSize : 10485760,
/**
* Regular expression of file name to exclude when uploading folder
*
* @type Object
* @default { win: /^(?:desktop\.ini|thumbs\.db)$/i, mac: /^\.ds_store$/i }
*/
folderUploadExclude : {
win: /^(?:desktop\.ini|thumbs\.db)$/i,
mac: /^\.ds_store$/i
},
/**
* Timeout for upload using iframe
*
* @type Number
* @default 0 - no timeout
*/
iframeTimeout : 0,
/**
* Data to append to all requests and to upload files
*
* @type Object
* @default {}
*/
customData : {},
/**
* Event listeners to bind on elFinder init
*
* @type Object
* @default {}
*/
handlers : {},
/**
* Any custom headers to send across every ajax request
*
* @type Object
* @default {}
*/
customHeaders : {},
/**
* Any custom xhrFields to send across every ajax request
*
* @type Object
* @default {}
*/
xhrFields : {},
/**
* Interface language
*
* @type String
* @default "en"
*/
lang : 'en',
/**
* Base URL of elfFinder library starting from Manager HTML
* Auto detect when empty value
*
* @type String
* @default ""
*/
baseUrl : '',
/**
* Base URL of i18n js files
* baseUrl + "js/i18n/" when empty value
*
* @type String
* @default ""
*/
i18nBaseUrl : '',
/**
* Auto load required CSS
* `false` to disable this function or
* CSS URL Array to load additional CSS files
*
* @type Boolean|Array
* @default true
*/
cssAutoLoad : true,
/**
* Theme to load
* {"themeid" : "Theme CSS URL"} or
* {"themeid" : "Theme manifesto.json URL"} or
* Theme manifesto.json Object
* {
* "themeid" : {
* "name":"Theme Name",
* "cssurls":"Theme CSS URL",
* "author":"Author Name",
* "email":"Author Email",
* "license":"License",
* "link":"Web Site URL",
* "image":"Screen Shot URL",
* "description":"Description"
* }
* }
*
* @type Object
*/
themes : {},
/**
* Theme id to initial theme
*
* @type String|Null
*/
theme : null,
/**
* Additional css class for filemanager node.
*
* @type String
*/
cssClass : '',
/**
* Active commands list. '*' means all of the commands that have been load.
* If some required commands will be missed here, elFinder will add its
*
* @type Array
*/
commands : ['*'],
// Available commands list
//commands : [
// 'archive', 'back', 'chmod', 'colwidth', 'copy', 'cut', 'download', 'duplicate', 'edit', 'extract',
// 'forward', 'fullscreen', 'getfile', 'help', 'home', 'info', 'mkdir', 'mkfile', 'netmount', 'netunmount',
// 'open', 'opendir', 'paste', 'places', 'quicklook', 'reload', 'rename', 'resize', 'restore', 'rm',
// 'search', 'sort', 'up', 'upload', 'view', 'zipdl'
//],
/**
* Commands options.
*
* @type Object
**/
commandsOptions : {
// // configure shortcuts of any command
// // add `shortcuts` property into each command
// any_command_name : {
// shortcuts : [] // for disable this command's shortcuts
// },
// any_command_name : {
// shortcuts : function(fm, shortcuts) {
// // for add `CTRL + E` for this command action
// shortcuts[0]['pattern'] += ' ctrl+e';
// return shortcuts;
// }
// },
// any_command_name : {
// shortcuts : function(fm, shortcuts) {
// // for full customize of this command's shortcuts
// return [ { pattern: 'ctrl+e ctrl+down numpad_enter' + (fm.OS != 'mac' && ' enter') } ];
// }
// },
// "getfile" command options.
getfile : {
onlyURL : false,
// allow to return multiple files info
multiple : false,
// allow to return filers info
folders : false,
// action after callback (""/"close"/"destroy")
oncomplete : '',
// action when callback is fail (""/"close"/"destroy")
onerror : '',
// get path before callback call
getPath : true,
// get image sizes before callback call
getImgSize : false
},
open : {
// HTTP method that request to the connector when item URL is not valid URL.
// If you set to "get" will be displayed request parameter in the browser's location field
// so if you want to conceal its parameters should be given "post".
// Nevertheless, please specify "get" if you want to enable the partial request by HTTP Range header.
method : 'post',
// Where to open into : 'window'(default), 'tab' or 'tabs'
// 'tabs' opens in each tabs
into : 'window',
// Default command list of action when select file
// String value that is 'Command Name' or 'Command Name1/CommandName2...'
selectAction : 'open'
},
opennew : {
// URL of to open elFinder manager
// Default '' : Origin URL
url : '',
// Use search query of origin URL
useOriginQuery : true
},
// "upload" command options.
upload : {
// Open elFinder upload dialog: 'button' OR Open system OS upload dialog: 'uploadbutton'
ui : 'button'
},
// "download" command options.
download : {
// max request to download files when zipdl disabled
maxRequests : 10,
// minimum count of files to use zipdl
minFilesZipdl : 2
},
// "quicklook" command options.
quicklook : {
autoplay : true,
width : 450,
height : 300,
// ControlsList of HTML5 audio/video preview
// see https://googlechrome.github.io/samples/media/controlslist.html
mediaControlsList : '', // e.g. 'nodownload nofullscreen noremoteplayback'
// Show toolbar of PDF preview (with <embed> tag)
pdfToolbar : true,
// Maximum characters length to preview
textMaxlen : 2000,
// quicklook window must be contained in elFinder node on window open (true|false)
contain : false,
// preview window into NavDock (0 : undocked | 1 : docked(show) | 2 : docked(hide))
docked : 0,
// Docked preview height ('auto' or Number of pixel) 'auto' is setted to the Navbar width
dockHeight : 'auto',
// media auto play when docked
dockAutoplay : false,
// Google Maps API key (Require Maps JavaScript API)
googleMapsApiKey : '',
// Google Maps API Options
googleMapsOpts : {
maps : {},
kml : {
suppressInfoWindows : false,
preserveViewport : false
}
},
// ViewerJS (https://viewerjs.org/) Options
// To enable this you need to place ViewerJS on the same server as elFinder and specify that URL in `url`.
viewerjs : {
url: '', // Example '/ViewerJS/index.html'
mimes: ['application/pdf', 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.presentation']
},
// MIME types to CAD-Files and 3D-Models online viewer on sharecad.org
// Example ['image/vnd.dwg', 'image/vnd.dxf', 'model/vnd.dwf', 'application/vnd.hp-hpgl', 'application/plt', 'application/step', 'model/iges', 'application/vnd.ms-pki.stl', 'application/sat', 'image/cgm', 'application/x-msmetafile']
sharecadMimes : [],
// MIME types to use Google Docs online viewer
// Example ['application/pdf', 'image/tiff', 'application/vnd.ms-office', 'application/msword', 'application/vnd.ms-word', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/postscript', 'application/rtf']
googleDocsMimes : [],
// MIME types to use Microsoft Office Online viewer
// Example ['application/msword', 'application/vnd.ms-word', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.presentation']
// These MIME types override "googleDocsMimes"
officeOnlineMimes : [],
// File size (byte) threshold when using the dim command for obtain the image size necessary to image preview
getDimThreshold : 200000,
// MIME-Type regular expression that does not check empty files
mimeRegexNotEmptyCheck : /^application\/vnd\.google-apps\./
},
// "quicklook" command options.
edit : {
// dialog width, integer(px) or integer+'%' (example: 650, '80%' ...)
dialogWidth : void(0),
// list of allowed mimetypes to edit of text files
// if empty - any text files can be edited
mimes : [],
// MIME-types of text file to make as empty files
makeTextMimes : ['text/plain', 'text/css', 'text/html'],
// Use the editor stored in the browser
// This value allowd overwrite with user preferences
useStoredEditor : false,
// Open the maximized editor window
// This value allowd overwrite with user preferences
editorMaximized : false,
// edit files in wysisyg's
editors : [
// {
// /**
// * editor info
// * @type Object
// */
// info : { name: 'Editor Name' },
// /**
// * files mimetypes allowed to edit in current wysisyg
// * @type Array
// */
// mimes : ['text/html'],
// /**
// * HTML element for editing area (optional for text editor)
// * @type String
// */
// html : '<textarea></textarea>',
// /**
// * Initialize editing area node (optional for text editor)
// *
// * @param String dialog DOM id
// * @param Object target file object
// * @param String target file content (text or Data URI Scheme(binary file))
// * @param Object elFinder instance
// * @type Function
// */
// init : function(id, file, content, fm) {
// $(this).attr('id', id + '-text').val(content);
// },
// /**
// * Get edited contents (optional for text editor)
// * @type Function
// */
// getContent : function() {
// return $(this).val();
// },
// /**
// * Called when "edit" dialog loaded.
// * Place to init wysisyg.
// * Can return wysisyg instance
// *
// * @param DOMElement textarea node
// * @return Object editor instance|jQuery.Deferred(return instance on resolve())
// */
// load : function(textarea) { },
// /**
// * Called before "edit" dialog closed.
// * Place to destroy wysisyg instance.
// *
// * @param DOMElement textarea node
// * @param Object wysisyg instance (if was returned by "load" callback)
// * @return void
// */
// close : function(textarea, instance) { },
// /**
// * Called before file content send to backend.
// * Place to update textarea content if needed.
// *
// * @param DOMElement textarea node
// * @param Object wysisyg instance (if was returned by "load" callback)
// * @return void
// */
// save : function(textarea, instance) {},
// /**
// * Called after load() or save().
// * Set focus to wysisyg editor.
// *
// * @param DOMElement textarea node
// * @param Object wysisyg instance (if was returned by "load" callback)
// * @return void
// */
// focus : function(textarea, instance) {}
// /**
// * Called after dialog resized..
// *
// * @param DOMElement textarea node
// * @param Object wysisyg instance (if was returned by "load" callback)
// * @param Object resize event object
// * @param Object data object
// * @return void
// */
// resize : function(textarea, instance, event, data) {}
//
// }
],
// Character encodings of select box
encodings : ['Big5', 'Big5-HKSCS', 'Cp437', 'Cp737', 'Cp775', 'Cp850', 'Cp852', 'Cp855', 'Cp857', 'Cp858',
'Cp862', 'Cp866', 'Cp874', 'EUC-CN', 'EUC-JP', 'EUC-KR', 'GB18030', 'ISO-2022-CN', 'ISO-2022-JP', 'ISO-2022-KR',
'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7',
'ISO-8859-8', 'ISO-8859-9', 'ISO-8859-13', 'ISO-8859-15', 'KOI8-R', 'KOI8-U', 'Shift-JIS',
'Windows-1250', 'Windows-1251', 'Windows-1252', 'Windows-1253', 'Windows-1254', 'Windows-1257'],
// options for extra editors
extraOptions : {
// TUI Image Editor's options
tuiImgEditOpts : {
// Path prefix of icon-a.svg, icon-b.svg, icon-c.svg and icon-d.svg in the Theme.
// `iconsPath` MUST follow the same origin policy.
iconsPath : void(0), // default is "./img/tui-"
// Theme object
theme : {}
},
// Specify the Creative Cloud API key when using Creative SDK image editor of Creative Cloud.
// You can get the API key at https://console.adobe.io/.
creativeCloudApiKey : '',
// Browsing manager URL for CKEditor, TinyMCE
// Uses self location with the empty value or not defined.
//managerUrl : 'elfinder.html'
managerUrl : null,
// CKEditor5' builds mode - 'classic', 'inline' or 'balloon'
ckeditor5Mode : 'balloon',
// Setting for Online-Convert.com
onlineConvert : {
maxSize : 100, // (MB) Max 100MB on free account
showLink : true // It must be enabled with free account
}
}
},
search : {
// Incremental search from the current view
incsearch : {
enable : true, // is enable true or false
minlen : 1, // minimum number of characters
wait : 500 // wait milliseconds
},
// Additional search types
searchTypes : {
// "SearchMime" is implemented in default
SearchMime : { // The key is search type that send to the connector
name : 'btnMime', // Button text to be processed in i18n()
title : 'searchMime' // Button title to be processed in i18n()
}
}
},
// "info" command options.
info : {
// If the URL of the Directory is null,
// it is assumed that the link destination is a URL to open the folder in elFinder
nullUrlDirLinkSelf : true,
// Information items to be hidden by default
// These name are 'size', 'aliasfor', 'path', 'link', 'dim', 'modify', 'perms', 'locked', 'owner', 'group', 'perm' and your custom info items label
hideItems : [],
// Maximum file size (byte) to get file contents hash (md5, sha256 ...)
showHashMaxsize : 104857600, // 100 MB
// Array of hash algorisms to show on info dialog
// These name are 'md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512', 'shake128' and 'shake256'
showHashAlgorisms : ['md5', 'sha256'],
custom : {
// /**
// * Example of custom info `desc`
// */
// desc : {
// /**
// * Lable (require)
// * It is filtered by the `fm.i18n()`
// *
// * @type String
// */
// label : 'Description',
//
// /**
// * Template (require)
// * `{id}` is replaced in dialog.id
// *
// * @type String
// */
// tpl : '<div class="elfinder-info-desc"><span class="elfinder-spinner"></span></div>',
//
// /**
// * Restricts to mimetypes (optional)
// * Exact match or category match
// *
// * @type Array
// */
// mimes : ['text', 'image/jpeg', 'directory'],
//
// /**
// * Restricts to file.hash (optional)
// *
// * @ type Regex
// */
// hashRegex : /^l\d+_/,
//
// /**
// * Request that asks for the description and sets the field (optional)
// *
// * @type Function
// */
// action : function(file, fm, dialog) {
// fm.request({
// data : { cmd : 'desc', target: file.hash },
// preventDefault: true,
// })
// .fail(function() {
// dialog.find('div.elfinder-info-desc').html(fm.i18n('unknown'));
// })
// .done(function(data) {
// dialog.find('div.elfinder-info-desc').html(data.desc);
// });
// }
// }
}
},
mkdir: {
// Enable automatic switching function ["New Folder" / "Into New Folder"] of toolbar buttton
intoNewFolderToolbtn: false
},
resize: {
// defalt status of snap to 8px grid of the jpeg image ("enable" or "disable")
grid8px : 'disable',
// Preset size array [width, height]
presetSize : [[320, 240], [400, 400], [640, 480], [800,600]],
// File size (bytes) threshold when using the `dim` command for obtain the image size necessary to start editing
getDimThreshold : 204800,
// File size (bytes) to request to get substitute image (400px) with the `dim` command
dimSubImgSize : 307200
},
rm: {
// If trash is valid, items moves immediately to the trash holder without confirm.
quickTrash : true,
// Maximum wait seconds when checking the number of items to into the trash
infoCheckWait : 10,
// Maximum number of items that can be placed into the Trash at one time
toTrashMaxItems : 1000
},
help : {
// Tabs to show
view : ['about', 'shortcuts', 'help', 'integrations', 'debug'],
// HTML source URL of the heip tab
helpSource : ''
},
preference : {
// dialog width
width: 600,
// dialog height
height: 400,
// tabs setting see preference.js : build()
categories: null,
// preference setting see preference.js : build()
prefs: null,
// language setting see preference.js : build()
langs: null,
// Command list of action when select file
// Array value are 'Command Name' or 'Command Name1/CommandName2...'
selectActions : ['open', 'edit/download', 'resize/edit/download', 'download', 'quicklook']
}
},
/**
* Callback for prepare boot up
*
* - The this object in the function is an elFinder node
* - The first parameter is elFinder Instance
* - The second parameter is an object of other parameters
* For now it can use `dfrdsBeforeBootup` Array
*
* @type Function
* @default null
* @return void
*/
bootCallback : null,
/**
* Callback for "getfile" commands.
* Required to use elFinder with WYSIWYG editors etc..
*
* @type Function
* @default null (command not active)
*/
getFileCallback : null,
/**
* Default directory view. icons/list
*
* @type String
* @default "icons"
*/
defaultView : 'icons',
/**
* Hash of default directory path to open
*
* NOTE: This setting will be disabled if the target folder is specified in location.hash.
*
* If you want to find the hash in Javascript
* can be obtained with the following code. (In the case of a standard hashing method)
*
* var volumeId = 'l1_'; // volume id
* var path = 'path/to/target'; // without root path
* //var path = 'path\\to\\target'; // use \ on windows server
* var hash = volumeId + btoa(path).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '.').replace(/\.+$/, '');
*
* @type String
* @default ""
*/
startPathHash : '',
/**
* Emit a sound when a file is deleted
* Sounds are in sounds/ folder
*
* @type Boolean
* @default true
*/
sound : true,
/**
* UI plugins to load.
* Current dir ui and dialogs loads always.
* Here set not required plugins as folders tree/toolbar/statusbar etc.
*
* @type Array
* @default ['toolbar', 'tree', 'path', 'stat']
* @full ['toolbar', 'places', 'tree', 'path', 'stat']
*/
ui : ['toolbar', 'tree', 'path', 'stat'],
/**
* Some UI plugins options.
* @type Object
*/
uiOptions : {
// toolbar configuration
toolbar : [
['home', 'back', 'forward', 'up', 'reload'],
['netmount'],
['mkdir', 'mkfile', 'upload'],
['open', 'download', 'getfile'],
['undo', 'redo'],
['copy', 'cut', 'paste', 'rm', 'empty', 'hide'],
['duplicate', 'rename', 'edit', 'resize', 'chmod'],
['selectall', 'selectnone', 'selectinvert'],
['quicklook', 'info'],
['extract', 'archive'],
['search'],
['view', 'sort'],
['preference', 'help'],
['fullscreen']
],
// toolbar extra options
toolbarExtra : {
// also displays the text label on the button (true / false / 'none')
displayTextLabel: false,
// Exclude `displayTextLabel` setting UA type
labelExcludeUA: ['Mobile'],
// auto hide on initial open
autoHideUA: ['Mobile'],
// Initial setting value of hide button in toolbar setting
defaultHides: ['home', 'reload'],
// show Preference button ('none', 'auto', 'always')
// If you do not include 'preference' in the context menu you should specify 'auto' or 'always'
showPreferenceButton: 'none',
// show Preference button into contextmenu of the toolbar (true / false)
preferenceInContextmenu: true
},
// directories tree options
tree : {
// expand current root on init
openRootOnLoad : true,
// expand current work directory on open
openCwdOnOpen : true,
// auto loading current directory parents and do expand their node.
syncTree : true,
// Maximum number of display of each child trees
// The tree of directories with children exceeding this number will be split
subTreeMax : 100,
// Numbar of max connctions of subdirs request
subdirsMaxConn : 2,
// Number of max simultaneous processing directory of subdirs
subdirsAtOnce : 5,
// Durations of each animations
durations : {
slideUpDown : 'fast',
autoScroll : 'fast'
}
// ,
// /**
// * Add CSS class name to navbar directories (optional)
// * see: https://github.com/Studio-42/elFinder/pull/1061,
// * https://github.com/Studio-42/elFinder/issues/1231
// *
// * @type Function
// */
// getClass: function(dir) {
// // e.g. This adds the directory's name (lowercase) with prefix as a CSS class
// return 'elfinder-tree-' + dir.name.replace(/[ "]/g, '').toLowerCase();
// }
},
// navbar options
navbar : {
minWidth : 150,
maxWidth : 500,
// auto hide on initial open
autoHideUA: [] // e.g. ['Mobile']
},
navdock : {
// disabled navdock ui
disabled : false,
// percentage of initial maximum height to work zone
initMaxHeight : '50%',
// percentage of maximum height to work zone by user resize action
maxHeight : '90%'
},
cwd : {
// display parent folder with ".." name :)
oldSchool : false,
// fm.UA types array to show item select checkboxes e.g. ['All'] or ['Mobile'] etc. default: ['Touch']
showSelectCheckboxUA : ['Touch'],
// file info columns displayed
listView : {
// name is always displayed, cols are ordered
// e.g. ['perm', 'date', 'size', 'kind', 'owner', 'group', 'mode']
// mode: 'mode'(by `fileModeStyle` setting), 'modestr'(rwxr-xr-x) , 'modeoct'(755), 'modeboth'(rwxr-xr-x (755))
// 'owner', 'group' and 'mode', It's necessary set volume driver option "statOwner" to `true`
// for custom, characters that can be used in the name is `a-z0-9_`
columns : ['perm', 'date', 'size', 'kind'],
// override this if you want custom columns name
// example
// columnsCustomName : {
// date : 'Last modification',
// kind : 'Mime type'
// }
columnsCustomName : {},
// fixed list header colmun
fixedHeader : true
},
// icons view setting
iconsView : {
// default icon size (0-3 in default CSS (cwd.css - elfinder-cwd-size[number]))
size: 0,
// number of maximum size (3 in default CSS (cwd.css - elfinder-cwd-size[number]))
// uses in preference.js
sizeMax: 3,
// Name of each size
sizeNames: {
0: 'viewSmall',
1: 'viewMedium',
2: 'viewLarge',
3: 'viewExtraLarge'
}
},
// /**
// * Add CSS class name to cwd directories (optional)
// * see: https://github.com/Studio-42/elFinder/pull/1061,
// * https://github.com/Studio-42/elFinder/issues/1231
// *
// * @type Function
// */
// ,
// getClass: function(file) {
// // e.g. This adds the directory's name (lowercase) with prefix as a CSS class
// return 'elfinder-cwd-' + file.name.replace(/[ "]/g, '').toLowerCase();
//}
//,
//// Template placeholders replacement rules for overwrite. see ui/cwd.js replacement
//replacement : {
// tooltip : function(f, fm) {
// var list = fm.viewType == 'list', // current view type
// query = fm.searchStatus.state == 2, // is in search results
// title = fm.formatDate(f) + (f.size > 0 ? ' ('+fm.formatSize(f.size)+')' : ''),
// info = '';
// if (query && f.path) {
// info = fm.escape(f.path.replace(/\/[^\/]*$/, ''));
// } else {
// info = f.tooltip? fm.escape(f.tooltip).replace(/\r/g, '&#13;') : '';
// }
// if (list) {
// info += (info? '&#13;' : '') + fm.escape(f.name);
// }
// return info? info + '&#13;' + title : title;
// }
//}
},
path : {
// Move to head of work zone without UI navbar
toWorkzoneWithoutNavbar : true
},
dialog : {
// Enable to auto focusing on mouse over in the target form element
focusOnMouseOver : true
},
toast : {
animate : {
// to show
showMethod: 'fadeIn', // fadeIn, slideDown, and show are built into jQuery
showDuration: 300, // milliseconds
showEasing: 'swing', // swing and linear are built into jQuery
// timeout to hide
timeOut: 3000,
// to hide
hideMethod: 'fadeOut',
hideDuration: 1500,
hideEasing: 'swing'
}
}
},
/**
* MIME regex of send HTTP header "Content-Disposition: inline" or allow preview in quicklook
* This option will overwrite by connector configuration
*
* @type String
* @default '^(?:(?:image|video|audio)|text/plain|application/pdf$)'
* @example
* dispInlineRegex : '.', // is allow inline of all of MIME types
* dispInlineRegex : '$^', // is not allow inline of all of MIME types
*/
dispInlineRegex : '^(?:(?:image|video|audio)|application/(?:x-mpegURL|dash\+xml)|(?:text/plain|application/pdf)$)',
/**
* Display only required files by types
*
* @type Array
* @default []
* @example
* onlyMimes : ["image"] - display all images
* onlyMimes : ["image/png", "application/x-shockwave-flash"] - display png and flash
*/
onlyMimes : [],
/**
* Custom files sort rules.
* All default rules (name/size/kind/date/perm/mode/owner/group) set in elFinder._sortRules
*
* @type {Object}
* @example
* sortRules : {
* name : function(file1, file2) { return file1.name.toLowerCase().localeCompare(file2.name.toLowerCase()); }
* }
*/
sortRules : {},
/**
* Default sort type.
*
* @type {String}
*/
sortType : 'name',
/**
* Default sort order.
*
* @type {String}
* @default "asc"
*/
sortOrder : 'asc',
/**
* Display folders first?
*
* @type {Boolean}
* @default true
*/
sortStickFolders : true,
/**
* Sort also applies to the treeview
*
* @type {Boolean}
* @default false
*/
sortAlsoTreeview : false,
/**
* If true - elFinder will formating dates itself,
* otherwise - backend date will be used.
*
* @type Boolean
*/
clientFormatDate : true,
/**
* Show UTC dates.
* Required set clientFormatDate to true
*
* @type Boolean
*/
UTCDate : false,
/**
* File modification datetime format.
* Value from selected language data is used by default.
* Set format here to overwrite it.
*
* @type String
* @default ""
*/
dateFormat : '',
/**
* File modification datetime format in form "Yesterday 12:23:01".
* Value from selected language data is used by default.
* Set format here to overwrite it.
* Use $1 for "Today"/"Yesterday" placeholder
*
* @type String
* @default ""
* @example "$1 H:m:i"
*/
fancyDateFormat : '',
/**
* Style of file mode at cwd-list, info dialog
* 'string' (ex. rwxr-xr-x) or 'octal' (ex. 755) or 'both' (ex. rwxr-xr-x (755))
*
* @type {String}
* @default 'both'
*/
fileModeStyle : 'both',
/**
* elFinder width
*
* @type String|Number
* @default "auto"
*/
width : 'auto',
/**
* elFinder node height
* Number: pixcel or String: Number + "%"
*
* @type Number | String
* @default 400
*/
height : 400,
/**
* Base node object or selector
* Element which is the reference of the height percentage
*
* @type Object|String
* @default null | $(window) (if height is percentage)
**/
heightBase : null,
/**
* Make elFinder resizable if jquery ui resizable available
*
* @type Boolean
* @default true
*/
resizable : true,
/**
* Timeout before open notifications dialogs
*
* @type Number
* @default 500 (.5 sec)
*/
notifyDelay : 500,
/**
* Position CSS, Width of notifications dialogs
*
* @type Object
* @default {position: {}, width : null} - Apply CSS definition
* position: CSS object | null (null: position center & middle)
*/
notifyDialog : {position: {}, width : null},
/**
* Dialog contained in the elFinder node
*
* @type Boolean
* @default false
*/
dialogContained : false,
/**
* Allow shortcuts
*
* @type Boolean
* @default true
*/
allowShortcuts : true,
/**
* Remeber last opened dir to open it after reload or in next session
*
* @type Boolean
* @default true
*/
rememberLastDir : true,
/**
* Clear historys(elFinder) on reload(not browser) function
* Historys was cleared on Reload function on elFinder 2.0 (value is true)
*
* @type Boolean
* @default false
*/
reloadClearHistory : false,
/**
* Use browser native history with supported browsers
*
* @type Boolean
* @default true
*/
useBrowserHistory : true,
/**
* Lazy load config.
* How many files display at once?
*
* @type Number
* @default 50
*/
showFiles : 50,
/**
* Lazy load config.
* Distance in px to cwd bottom edge to start display files
*
* @type Number
* @default 50
*/
showThreshold : 50,
/**
* Additional rule to valid new file name.
* By default not allowed empty names or '..'
* This setting does not have a sense of security.
*
* @type false|RegExp|function
* @default false
* @example
* disable names with spaces:
* validName : /^[^\s]+$/,
*/
validName : false,
/**
* Additional rule to filtering for browsing.
* This setting does not have a sense of security.
*
* The object `this` is elFinder instance object in this function
*
* @type false|RegExp|function
* @default false
* @example
* show only png and jpg files:
* fileFilter : /.*\.(png|jpg)$/i,
*
* show only image type files:
* fileFilter : function(file) { return file.mime && file.mime.match(/^image\//i); },
*/
fileFilter : false,
/**
* Backup name suffix.
*
* @type String
* @default "~"
*/
backupSuffix : '~',
/**
* Sync content interval
*
* @type Number
* @default 0 (do not sync)
*/
sync : 0,
/**
* Sync start on load if sync value >= 1000
*
* @type Bool
* @default true
*/
syncStart : true,
/**
* How many thumbnails create in one request
*
* @type Number
* @default 5
*/
loadTmbs : 5,
/**
* Cookie option for browsersdoes not suppot localStorage
*
* @type Object
*/
cookie : {
expires : 30,
domain : '',
path : '/',
secure : false
},
/**
* Contextmenu config
*
* @type Object
*/
contextmenu : {
// navbarfolder menu
navbar : ['open', 'opennew', 'download', '|', 'upload', 'mkdir', '|', 'copy', 'cut', 'paste', 'duplicate', '|', 'rm', 'empty', 'hide', '|', 'rename', '|', 'archive', '|', 'places', 'info', 'chmod', 'netunmount'],
// current directory menu
cwd : ['undo', 'redo', '|', 'back', 'up', 'reload', '|', 'upload', 'mkdir', 'mkfile', 'paste', '|', 'empty', 'hide', '|', 'view', 'sort', 'selectall', 'colwidth', '|', 'places', 'info', 'chmod', 'netunmount', '|', 'fullscreen', '|', 'preference'],
// current directory file menu
files : ['getfile', '|' ,'open', 'opennew', 'download', 'opendir', 'quicklook', '|', 'upload', 'mkdir', '|', 'copy', 'cut', 'paste', 'duplicate', '|', 'rm', 'empty', 'hide', '|', 'rename', 'edit', 'resize', '|', 'archive', 'extract', '|', 'selectall', 'selectinvert', '|', 'places', 'info', 'chmod', 'netunmount']
},
/**
* elFinder node enable always
* This value will set to `true` if <body> has elFinder node only
*
* @type Bool
* @default false
*/
enableAlways : false,
/**
* elFinder node enable by mouse over
*
* @type Bool
* @default true
*/
enableByMouseOver : true,
/**
* Show window close confirm dialog
* Value is which state to show
* 'hasNotifyDialog', 'editingFile', 'hasSelectedItem' and 'hasClipboardData'
*
* @type Array
* @default ['hasNotifyDialog', 'editingFile']
*/
windowCloseConfirm : ['hasNotifyDialog', 'editingFile'],
/**
* Function decoding 'raw' string converted to unicode
* It is used instead of fm.decodeRawString(str)
*
* @type Null|Function
*/
rawStringDecoder : typeof Encoding === 'object' && $.isFunction(Encoding.convert)? function(str) {
return Encoding.convert(str, {
to: 'UNICODE',
type: 'string'
});
} : null,
/**
* Debug config
*
* @type Array|String('auto')|Boolean(true|false)
*/
// debug : true
debug : ['error', 'warning', 'event-destroy']
};
/*
* File: /js/elFinder.options.netmount.js
*/
/**
* Default elFinder config of commandsOptions.netmount
*
* @type Object
*/
elFinder.prototype._options.commandsOptions.netmount = {
ftp: {
name : 'FTP',
inputs: {
host : $('<input type="text"/>'),
port : $('<input type="number" placeholder="21" class="elfinder-input-optional"/>'),
path : $('<input type="text" value="/"/>'),
user : $('<input type="text"/>'),
pass : $('<input type="password" autocomplete="new-password"/>'),
FTPS : $('<input type="checkbox" value="1" title="File Transfer Protocol over SSL/TLS"/>'),
encoding : $('<input type="text" placeholder="Optional" class="elfinder-input-optional"/>'),
locale : $('<input type="text" placeholder="Optional" class="elfinder-input-optional"/>')
}
},
dropbox2: elFinder.prototype.makeNetmountOptionOauth('dropbox2', 'Dropbox', 'Dropbox', {noOffline : true,
root : '/',
pathI18n : 'path',
integrate : {
title: 'Dropbox.com',
link: 'https://www.dropbox.com'
}
}),
googledrive: elFinder.prototype.makeNetmountOptionOauth('googledrive', 'Google Drive', 'Google', {
integrate : {
title: 'Google Drive',
link: 'https://www.google.com/drive/'
}
}),
onedrive: elFinder.prototype.makeNetmountOptionOauth('onedrive', 'One Drive', 'OneDrive', {
integrate : {
title: 'Microsoft OneDrive',
link: 'https://onedrive.live.com'
}
}),
box: elFinder.prototype.makeNetmountOptionOauth('box', 'Box', 'Box', {
noOffline : true,
integrate : {
title: 'Box.com',
link: 'https://www.box.com'
}
})
};
/*
* File: /js/elFinder.history.js
*/
/**
* @class elFinder.history
* Store visited folders
* and provide "back" and "forward" methods
*
* @author Dmitry (dio) Levashov
*/
elFinder.prototype.history = function(fm) {
var self = this,
/**
* Update history on "open" event?
*
* @type Boolean
*/
update = true,
/**
* Directories hashes storage
*
* @type Array
*/
history = [],
/**
* Current directory index in history
*
* @type Number
*/
current,
/**
* Clear history
*
* @return void
*/
reset = function() {
history = [fm.cwd().hash];
current = 0;
update = true;
},
/**
* Browser native history object
*/
nativeHistory = (fm.options.useBrowserHistory && window.history && window.history.pushState)? window.history : null,
/**
* Open prev/next folder
*
* @Boolen open next folder?
* @return jQuery.Deferred
*/
go = function(fwd) {
if ((fwd && self.canForward()) || (!fwd && self.canBack())) {
update = false;
return fm.exec('open', history[fwd ? ++current : --current]).fail(reset);
}
return $.Deferred().reject();
},
/**
* Sets the native history.
*
* @param String thash target hash
*/
setNativeHistory = function(thash) {
if (nativeHistory && (! nativeHistory.state || nativeHistory.state.thash !== thash)) {
nativeHistory.pushState({thash: thash}, null, location.pathname + location.search + (thash? '#elf_' + thash : ''));
}
};
/**
* Return true if there is previous visited directories
*
* @return Boolen
*/
this.canBack = function() {
return current > 0;
};
/**
* Return true if can go forward
*
* @return Boolen
*/
this.canForward = function() {
return current < history.length - 1;
};
/**
* Go back
*
* @return void
*/
this.back = go;
/**
* Go forward
*
* @return void
*/
this.forward = function() {
return go(true);
};
// bind to elfinder events
fm.bind('init', function() {
if (nativeHistory && !nativeHistory.state) {
setNativeHistory(fm.startDir());
}
})
.open(function() {
var l = history.length,
cwd = fm.cwd().hash;
if (update) {
current >= 0 && l > current + 1 && history.splice(current+1);
history[history.length-1] != cwd && history.push(cwd);
current = history.length - 1;
}
update = true;
setNativeHistory(cwd);
})
.reload(fm.options.reloadClearHistory && reset);
};
/*
* File: /js/elFinder.command.js
*/
/**
* elFinder command prototype
*
* @type elFinder.command
* @author Dmitry (dio) Levashov
*/
elFinder.prototype.command = function(fm) {
/**
* elFinder instance
*
* @type elFinder
*/
this.fm = fm;
/**
* Command name, same as class name
*
* @type String
*/
this.name = '';
/**
* Dialog class name
*
* @type String
*/
this.dialogClass = '';
/**
* Command icon class name with out 'elfinder-button-icon-'
* Use this.name if it is empty
*
* @type String
*/
this.className = '';
/**
* Short command description
*
* @type String
*/
this.title = '';
/**
* Linked(Child) commands name
* They are loaded together when tthis command is loaded.
*
* @type Array
*/
this.linkedCmds = [];
/**
* Current command state
*
* @example
* this.state = -1; // command disabled
* this.state = 0; // command enabled
* this.state = 1; // command active (for example "fullscreen" command while elfinder in fullscreen mode)
* @default -1
* @type Number
*/
this.state = -1;
/**
* If true, command can not be disabled by connector.
* @see this.update()
*
* @type Boolen
*/
this.alwaysEnabled = false;
/**
* Do not change dirctory on removed current work directory
*
* @type Boolen
*/
this.noChangeDirOnRemovedCwd = false;
/**
* If true, this means command was disabled by connector.
* @see this.update()
*
* @type Boolen
*/
this._disabled = false;
/**
* If true, this command is disabled on serach results
*
* @type Boolean
*/
this.disableOnSearch = false;
/**
* Call update() when event select fired
*
* @type Boolean
*/
this.updateOnSelect = true;
/**
* Sync toolbar button title on change
*
* @type Boolean
*/
this.syncTitleOnChange = false;
/**
* Keep display of the context menu when command execution
*
* @type Boolean
*/
this.keepContextmenu = false;
/**
* elFinder events defaults handlers.
* Inside handlers "this" is current command object
*
* @type Object
*/
this._handlers = {
enable : function() { this.update(void(0), this.value); },
disable : function() { this.update(-1, this.value); },
'open reload load sync' : function() {
this._disabled = !(this.alwaysEnabled || this.fm.isCommandEnabled(this.name));
this.update(void(0), this.value);
this.change();
}
};
/**
* elFinder events handlers.
* Inside handlers "this" is current command object
*
* @type Object
*/
this.handlers = {};
/**
* Shortcuts
*
* @type Array
*/
this.shortcuts = [];
/**
* Command options
*
* @type Object
*/
this.options = {ui : 'button'};
/**
* Callback functions on `change` event
*
* @type Array
*/
this.listeners = [];
/**
* Prepare object -
* bind events and shortcuts
*
* @return void
*/
this.setup = function(name, opts) {
var self = this,
fm = this.fm,
setCallback = function(s) {
var cb = s.callback || function(e) {
fm.exec(self.name, void(0), {
_userAction: true,
_currentType: 'shortcut'
});
};
s.callback = function(e) {
var enabled, checks = {};
if (self.enabled()) {
if (fm.searchStatus.state < 2) {
enabled = fm.isCommandEnabled(self.name);
} else {
$.each(fm.selected(), function(i, h) {
if (fm.optionsByHashes[h]) {
checks[h] = true;
} else {
$.each(fm.volOptions, function(id) {
if (!checks[id] && h.indexOf(id) === 0) {
checks[id] = true;
return false;
}
});
}
});
$.each(checks, function(h) {
enabled = fm.isCommandEnabled(self.name, h);
if (! enabled) {
return false;
}
});
}
if (enabled) {
self.event = e;
cb.call(self);
delete self.event;
}
}
};
},
i, s, sc;
this.name = name;
this.title = fm.messages['cmd'+name] ? fm.i18n('cmd'+name)
: ((this.extendsCmd && fm.messages['cmd'+this.extendsCmd]) ? fm.i18n('cmd'+this.extendsCmd) : name);
this.options = Object.assign({}, this.options, opts);
this.listeners = [];
this.dialogClass = 'elfinder-dialog-' + name;
if (opts.shortcuts) {
if (typeof opts.shortcuts === 'function') {
sc = opts.shortcuts(this.fm, this.shortcuts);
} else if (Array.isArray(opts.shortcuts)) {
sc = opts.shortcuts;
}
this.shortcuts = sc || [];
}
if (this.updateOnSelect) {
this._handlers.select = function() { this.update(void(0), this.value); };
}
$.each(Object.assign({}, self._handlers, self.handlers), function(cmd, handler) {
fm.bind(cmd, $.proxy(handler, self));
});
for (i = 0; i < this.shortcuts.length; i++) {
s = this.shortcuts[i];
setCallback(s);
!s.description && (s.description = this.title);
fm.shortcut(s);
}
if (this.disableOnSearch) {
fm.bind('search searchend', function() {
self._disabled = this.type === 'search'? true : ! (this.alwaysEnabled || fm.isCommandEnabled(name));
self.update(void(0), self.value);
});
}
this.init();
};
/**
* Command specific init stuffs
*
* @return void
*/
this.init = function() {};
/**
* Exec command
*
* @param Array target files hashes
* @param Array|Object command value
* @return $.Deferred
*/
this.exec = function(files, opts) {
return $.Deferred().reject();
};
this.getUndo = function(opts, resData) {
return false;
};
/**
* Return true if command disabled.
*
* @return Boolen
*/
this.disabled = function() {
return this.state < 0;
};
/**
* Return true if command enabled.
*
* @return Boolen
*/
this.enabled = function() {
return this.state > -1;
};
/**
* Return true if command active.
*
* @return Boolen
*/
this.active = function() {
return this.state > 0;
};
/**
* Return current command state.
* Must be overloaded in most commands
*
* @return Number
*/
this.getstate = function() {
return -1;
};
/**
* Update command state/value
* and rize 'change' event if smth changed
*
* @param Number new state or undefined to auto update state
* @param mixed new value
* @return void
*/
this.update = function(s, v) {
var state = this.state,
value = this.value;
if (this._disabled && this.fm.searchStatus === 0) {
this.state = -1;
} else {
this.state = s !== void(0) ? s : this.getstate();
}
this.value = v;
if (state != this.state || value != this.value) {
this.change();
}
};
/**
* Bind handler / fire 'change' event.
*
* @param Function|undefined event callback
* @return void
*/
this.change = function(c) {
var cmd, i;
if (typeof(c) === 'function') {
this.listeners.push(c);
} else {
for (i = 0; i < this.listeners.length; i++) {
cmd = this.listeners[i];
try {
cmd(this.state, this.value);
} catch (e) {
this.fm.debug('error', e);
}
}
}
return this;
};
/**
* With argument check given files hashes and return list of existed files hashes.
* Without argument return selected files hashes.
*
* @param Array|String|void hashes
* @return Array
*/
this.hashes = function(hashes) {
return hashes
? $.grep(Array.isArray(hashes) ? hashes : [hashes], function(hash) { return fm.file(hash) ? true : false; })
: fm.selected();
};
/**
* Return only existed files from given fils hashes | selected files
*
* @param Array|String|void hashes
* @return Array
*/
this.files = function(hashes) {
var fm = this.fm;
return hashes
? $.map(Array.isArray(hashes) ? hashes : [hashes], function(hash) { return fm.file(hash) || null; })
: fm.selectedFiles();
};
/**
* Wrapper to fm.dialog()
*
* @param String|DOMElement content
* @param Object options
* @return Object jQuery element object
*/
this.fmDialog = function(content, options) {
if (options.cssClass) {
options.cssClass += ' ' + this.dialogClass;
} else {
options.cssClass = this.dialogClass;
}
return this.fm.dialog(content, options);
};
};
/*
* File: /js/elFinder.resources.js
*/
/**
* elFinder resources registry.
* Store shared data
*
* @type Object
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.resources = {
'class' : {
hover : 'ui-state-hover',
active : 'ui-state-active',
disabled : 'ui-state-disabled',
draggable : 'ui-draggable',
droppable : 'ui-droppable',
adroppable : 'elfinder-droppable-active',
cwdfile : 'elfinder-cwd-file',
cwd : 'elfinder-cwd',
tree : 'elfinder-tree',
treeroot : 'elfinder-navbar-root',
navdir : 'elfinder-navbar-dir',
navdirwrap : 'elfinder-navbar-dir-wrapper',
navarrow : 'elfinder-navbar-arrow',
navsubtree : 'elfinder-navbar-subtree',
navcollapse : 'elfinder-navbar-collapsed',
navexpand : 'elfinder-navbar-expanded',
treedir : 'elfinder-tree-dir',
placedir : 'elfinder-place-dir',
searchbtn : 'elfinder-button-search',
editing : 'elfinder-to-editing',
preventback : 'elfinder-prevent-back',
tabstab : 'ui-state-default ui-tabs-tab ui-corner-top ui-tab',
tabsactive : 'ui-tabs-active ui-state-active'
},
tpl : {
perms : '<span class="elfinder-perms"/>',
lock : '<span class="elfinder-lock"/>',
symlink : '<span class="elfinder-symlink"/>',
navicon : '<span class="elfinder-nav-icon"/>',
navspinner : '<span class="elfinder-spinner elfinder-navbar-spinner"/>',
navdir : '<div class="elfinder-navbar-wrapper{root}"><span id="{id}" class="ui-corner-all elfinder-navbar-dir {cssclass}"><span class="elfinder-navbar-arrow"/><span class="elfinder-navbar-icon" {style}/>{symlink}{permissions}{name}</span><div class="elfinder-navbar-subtree" style="display:none"/></div>',
placedir : '<div class="elfinder-navbar-wrapper"><span id="{id}" class="ui-corner-all elfinder-navbar-dir {cssclass}" title="{title}"><span class="elfinder-navbar-arrow"/><span class="elfinder-navbar-icon" {style}/>{symlink}{permissions}{name}</span><div class="elfinder-navbar-subtree" style="display:none"/></div>'
},
// mimes.text will be overwritten with connector config if `textMimes` is included in initial response
// @see php/elFInder.class.php `public static $textMimes`
mimes : {
text : [
'application/dash+xml',
'application/docbook+xml',
'application/javascript',
'application/json',
'application/plt',
'application/sat',
'application/sql',
'application/step',
'application/vnd.hp-hpgl',
'application/x-awk',
'application/x-config',
'application/x-csh',
'application/x-empty',
'application/x-mpegurl',
'application/x-perl',
'application/x-php',
'application/x-web-config',
'application/xhtml+xml',
'application/xml',
'audio/x-mp3-playlist',
'image/cgm',
'image/svg+xml',
'image/vnd.dxf',
'model/iges'
]
},
mixin : {
make : function() {
var self = this,
fm = this.fm,
cmd = this.name,
req = this.requestCmd || cmd,
wz = fm.getUI('workzone'),
org = (this.origin && this.origin === 'navbar')? 'tree' : 'cwd',
ui = fm.getUI(org),
tree = (org === 'tree'),
find = tree? 'navHash2Id' : 'cwdHash2Id',
tarea= (! tree && fm.storage('view') != 'list'),
sel = fm.selected(),
move = this.move || false,
empty= wz.hasClass('elfinder-cwd-wrapper-empty'),
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) {
nnode && nnode.css('max-height', '');
} else if (!tree) {
pnode.css('width', '')
.parent('td').css('overflow', '');
}
}, colwidth,
dfrd = $.Deferred()
.fail(function(error) {
dstCls && dst.attr('class', dstCls);
empty && wz.addClass('elfinder-cwd-wrapper-empty');
if (sel) {
move && fm.trigger('unlockfiles', {files: sel});
fm.clipboard([]);
fm.trigger('selectfiles', { files: sel });
}
error && fm.error(error);
})
.always(function() {
rest();
cleanup();
fm.enable().unbind('open', openCallback).trigger('resMixinMake');
}),
id = 'tmp_'+parseInt(Math.random()*100000),
phash = this.data && this.data.target? this.data.target : (tree? fm.file(sel[0]).hash : fm.cwd().hash),
date = new Date(),
file = {
hash : id,
phash : phash,
name : fm.uniqueName(this.prefix, phash),
mime : this.mime,
read : true,
write : true,
date : 'Today '+date.getHours()+':'+date.getMinutes(),
move : move
},
data = this.data || {},
node = ui.trigger('create.'+fm.namespace, file).find('#'+fm[find](id)),
nnode, pnode,
overlay = fm.getUI('overlay'),
cleanup = function() {
if (node && node.length) {
input.off();
node.hide();
fm.unselectfiles({files : [id]}).unbind('resize', resize);
requestAnimationFrame(function() {
if (tree) {
node.closest('.elfinder-navbar-wrapper').remove();
} else {
node.remove();
}
});
}
},
cancel = function(e) {
if (!overlay.is(':hidden')) {
pnode.css('z-index', '');
}
if (! inError) {
cleanup();
dfrd.reject();
if (e) {
e.stopPropagation();
e.preventDefault();
}
}
},
input = $(tarea? '<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) {
input.trigger('blur');
}
})
.on('mousedown click dblclick', function(e) {
e.stopPropagation();
if (e.type === 'dblclick') {
e.preventDefault();
}
})
.on('blur', function() {
var name = $.trim(input.val()),
parent = input.parent(),
valid = true,
cut;
if (!overlay.is(':hidden')) {
pnode.css('z-index', '');
}
if (name === '') {
return cancel();
}
if (!inError && parent.length) {
if (fm.options.validName && fm.options.validName.test) {
try {
valid = fm.options.validName.test(name);
} catch(e) {
valid = false;
}
}
if (!name || name === '.' || name === '..' || !valid) {
inError = true;
fm.error(file.mime === 'directory'? 'errInvDirname' : 'errInvName', {modal: true, close: function(){setTimeout(select, 120);}});
return false;
}
if (fm.fileByName(name, phash)) {
inError = true;
fm.error(['errExists', name], {modal: true, close: function(){setTimeout(select, 120);}});
return false;
}
cut = (sel && move)? fm.exec('cut', sel) : null;
$.when(cut)
.done(function() {
var toast = {},
nextAct = {};
rest();
input.hide().before($('<span>').text(name));
fm.lockfiles({files : [id]});
fm.request({
data : Object.assign({cmd : req, name : name, target : phash}, data || {}),
notify : {type : req, cnt : 1},
preventFail : true,
syncOnFail : true,
navigate : {toast : toast},
})
.fail(function(error) {
fm.unlockfiles({files : [id]});
inError = true;
input.show().prev().remove();
fm.error(error, {
modal: true,
close: function() {
if (Array.isArray(error) && $.inArray('errUploadMime', error) !== -1) {
dfrd.notify('errUploadMime').reject();
} else {
setTimeout(select, 120);
}
}
});
})
.done(function(data) {
if (data && data.added && data.added[0]) {
var item = data.added[0],
dirhash = item.hash,
newItem = ui.find('#'+fm[find](dirhash)),
acts = {
'directory' : { cmd: 'open', msg: 'cmdopendir' },
'text' : { cmd: 'edit', msg: 'cmdedit' },
'default' : { cmd: 'open', msg: 'cmdopen' }
},
tmpMimes;
if (sel && move) {
fm.one(req+'done', function() {
fm.exec('paste', dirhash);
});
}
if (!move) {
if (fm.mimeIsText(item.mime) && !fm.mimesCanMakeEmpty[item.mime] && fm.mimeTypes[item.mime]) {
fm.trigger('canMakeEmptyFile', {mimes: [item.mime], unshift: true});
tmpMimes = {};
tmpMimes[item.mime] = fm.mimeTypes[item.mime];
fm.storage('mkfileTextMimes', Object.assign(tmpMimes, fm.storage('mkfileTextMimes') || {}));
}
Object.assign(nextAct, nextAction || acts[item.mime] || acts[item.mime.split('/')[0]] || acts[(fm.mimesCanMakeEmpty[item.mime] || $.inArray(item.mime, fm.resources.mimes.text) !== -1) ? 'text' : 'none'] || acts['default']);
Object.assign(toast, nextAct.cmd ? {
incwd : {msg: fm.i18n(['complete', fm.i18n('cmd'+cmd)]), action: nextAct},
inbuffer : {msg: fm.i18n(['complete', fm.i18n('cmd'+cmd)]), action: nextAct}
} : {
inbuffer : {msg: fm.i18n(['complete', fm.i18n('cmd'+cmd)])}
});
}
}
dfrd.resolve(data);
});
})
.fail(function() {
dfrd.reject();
});
}
})
.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);
}
inError = false;
! fm.enabled() && fm.enable();
input.trigger('focus').trigger('select');
input[0].setSelectionRange && input[0].setSelectionRange(0, name.length);
},
resize = function() {
node.trigger('scrolltoview', {blink : false});
},
openCallback = function() {
dfrd && (dfrd.state() === 'pending') && dfrd.reject();
},
inError = false,
nextAction,
// for tree
dst, dstCls, collapsed, expanded, arrow, subtree;
if (!fm.isCommandEnabled(req, phash) || !node.length) {
return dfrd.reject();
}
if ($.isPlainObject(self.nextAction)){
nextAction = Object.assign({}, self.nextAction);
}
if (tree) {
dst = $('#'+fm[find](phash));
collapsed = fm.res('class', 'navcollapse');
expanded = fm.res('class', 'navexpand');
arrow = fm.res('class', 'navarrow');
subtree = fm.res('class', 'navsubtree');
node.closest('.'+subtree).show();
if (! dst.hasClass(collapsed)) {
dstCls = dst.attr('class');
dst.addClass(collapsed+' '+expanded+' elfinder-subtree-loaded');
}
if (dst.is('.'+collapsed+':not(.'+expanded+')')) {
dst.children('.'+arrow).trigger('click').data('dfrd').done(function() {
if (input.val() === file.name) {
input.val(fm.uniqueName(self.prefix, phash)).trigger('select').trigger('focus');
}
});
}
nnode = node.contents().filter(function(){ return this.nodeType==3 && $(this).parent().attr('id') === fm.navHash2Id(file.hash); });
pnode = nnode.parent();
nnode.replaceWith(input.val(file.name));
} else {
empty && wz.removeClass('elfinder-cwd-wrapper-empty');
nnode = node.find('.elfinder-cwd-filename');
pnode = nnode.parent();
if (tarea) {
nnode.css('max-height', 'none');
} else {
colwidth = pnode.width();
pnode.width(colwidth - 15)
.parent('td').css('overflow', 'visible');
}
nnode.empty().append(input.val(file.name));
}
pnode.addClass('ui-front')
.css('position', 'relative')
.on('unselect.'+fm.namespace, unselect);
fm.bind('resize', resize).one('open', openCallback);
input.trigger('keyup');
select();
return dfrd;
}
},
blink: function(elm, mode) {
var acts = {
slowonce : function(){elm.hide().delay(250).fadeIn(750).delay(500).fadeOut(3500);},
lookme : function(){elm.show().fadeOut(500).fadeIn(750);}
}, func;
mode = mode || 'slowonce';
func = acts[mode] || acts['lookme'];
elm.stop(true, true);
func();
}
};
/*
* File: /js/jquery.dialogelfinder.js
*/
/**
* @class dialogelfinder - open elFinder in dialog window
*
* @param Object elFinder options with dialog options
* @example
* $(selector).dialogelfinder({
* // some elfinder options
* title : 'My files', // dialog title, default = "Files"
* width : 850, // dialog width, default 840
* autoOpen : false, // if false - dialog will not be opened after init, default = true
* destroyOnClose : true // destroy elFinder on close dialog, default = false
* })
* @author Dmitry (dio) Levashov
**/
$.fn.dialogelfinder = function(opts) {
var position = 'elfinderPosition',
destroy = 'elfinderDestroyOnClose',
node;
this.not('.elfinder').each(function() {
var doc = $(document),
toolbar = $('<div class="ui-widget-header dialogelfinder-drag ui-corner-top">'+(opts.title || 'Files')+'</div>'),
button = $('<a href="#" class="dialogelfinder-drag-close ui-corner-all"><span class="ui-icon ui-icon-closethick"> </span></a>')
.appendTo(toolbar)
.on('click', function(e) {
e.preventDefault();
node.dialogelfinder('close');
}),
node = $(this).addClass('dialogelfinder')
.css('position', 'absolute')
.hide()
.appendTo('body')
.draggable({
handle : '.dialogelfinder-drag',
containment : 'window',
stop : function() {
node.trigger('resize');
elfinder.trigger('resize');
}
})
.elfinder(opts)
.prepend(toolbar),
elfinder = node.elfinder('instance');
node.width(parseInt(node.width()) || 840) // fix width if set to "auto"
.data(destroy, !!opts.destroyOnClose)
.find('.elfinder-toolbar').removeClass('ui-corner-top');
opts.position && node.data(position, opts.position);
opts.autoOpen !== false && $(this).dialogelfinder('open');
});
if (opts == 'open') {
var node = $(this),
pos = node.data(position) || {
top : parseInt($(document).scrollTop() + ($(window).height() < node.height() ? 2 : ($(window).height() - node.height())/2)),
left : parseInt($(document).scrollLeft() + ($(window).width() < node.width() ? 2 : ($(window).width() - node.width())/2))
};
if (node.is(':hidden')) {
node.addClass('ui-front').css(pos).show().trigger('resize');
setTimeout(function() {
// fix resize icon position and make elfinder active
node.trigger('resize').trigger('mousedown');
}, 200);
}
} else if (opts == 'close') {
node = $(this).removeClass('ui-front');
if (node.is(':visible')) {
!!node.data(destroy)
? node.elfinder('destroy').remove()
: node.elfinder('close');
}
} else if (opts == 'instance') {
return $(this).getElFinder();
}
return this;
};
/*
* File: /js/i18n/elfinder.en.js
*/
/**
* English translation
* @author Troex Nevelin <troex@fury.scancode.ru>
* @author Naoki Sawada <hypweb+elfinder@gmail.com>
* @version 2018-10-19
*/
// elfinder.en.js is integrated into elfinder.(full|min).js by jake build
if (typeof elFinder === 'function' && elFinder.prototype.i18) {
elFinder.prototype.i18.en = {
translator : 'Troex Nevelin &lt;troex@fury.scancode.ru&gt;, Naoki Sawada &lt;hypweb+elfinder@gmail.com&gt;',
language : 'English',
direction : 'ltr',
dateFormat : 'M d, Y h:i A', // will show like: Aug 24, 2018 04:39 PM
fancyDateFormat : '$1 h:i A', // will show like: Today 04:39 PM
nonameDateFormat : 'ymd-His', // noname upload will show like: 180824-163916
messages : {
/********************************** errors **********************************/
'error' : 'Error',
'errUnknown' : 'Unknown error.',
'errUnknownCmd' : 'Unknown command.',
'errJqui' : 'Invalid jQuery UI configuration. Selectable, draggable and droppable components must be included.',
'errNode' : 'elFinder requires DOM Element to be created.',
'errURL' : 'Invalid elFinder configuration! URL option is not set.',
'errAccess' : 'Access denied.',
'errConnect' : 'Unable to connect to backend.',
'errAbort' : 'Connection aborted.',
'errTimeout' : 'Connection timeout.',
'errNotFound' : 'Backend not found.',
'errResponse' : 'Invalid backend response.',
'errConf' : 'Invalid backend configuration.',
'errJSON' : 'PHP JSON module not installed.',
'errNoVolumes' : 'Readable volumes not available.',
'errCmdParams' : 'Invalid parameters for command "$1".',
'errDataNotJSON' : 'Data is not JSON.',
'errDataEmpty' : 'Data is empty.',
'errCmdReq' : 'Backend request requires command name.',
'errOpen' : 'Unable to open "$1".',
'errNotFolder' : 'Object is not a folder.',
'errNotFile' : 'Object is not a file.',
'errRead' : 'Unable to read "$1".',
'errWrite' : 'Unable to write into "$1".',
'errPerm' : 'Permission denied.',
'errLocked' : '"$1" is locked and can not be renamed, moved or removed.',
'errExists' : 'Item named "$1" already exists.',
'errInvName' : 'Invalid file name.',
'errInvDirname' : 'Invalid folder name.', // from v2.1.24 added 12.4.2017
'errFolderNotFound' : 'Folder not found.',
'errFileNotFound' : 'File not found.',
'errTrgFolderNotFound' : 'Target folder "$1" not found.',
'errPopup' : 'Browser prevented opening popup window. To open file enable it in browser options.',
'errMkdir' : 'Unable to create folder "$1".',
'errMkfile' : 'Unable to create file "$1".',
'errRename' : 'Unable to rename "$1".',
'errCopyFrom' : 'Copying files from volume "$1" not allowed.',
'errCopyTo' : 'Copying files to volume "$1" not allowed.',
'errMkOutLink' : 'Unable to create a link to outside the volume root.', // from v2.1 added 03.10.2015
'errUpload' : 'Upload error.', // old name - errUploadCommon
'errUploadFile' : 'Unable to upload "$1".', // old name - errUpload
'errUploadNoFiles' : 'No files found for upload.',
'errUploadTotalSize' : 'Data exceeds the maximum allowed size.', // old name - errMaxSize
'errUploadFileSize' : 'File exceeds maximum allowed size.', // old name - errFileMaxSize
'errUploadMime' : 'File type not allowed.',
'errUploadTransfer' : '"$1" transfer error.',
'errUploadTemp' : 'Unable to make temporary file for upload.', // from v2.1 added 26.09.2015
'errNotReplace' : 'Object "$1" already exists at this location and can not be replaced by object with another type.', // new
'errReplace' : 'Unable to replace "$1".',
'errSave' : 'Unable to save "$1".',
'errCopy' : 'Unable to copy "$1".',
'errMove' : 'Unable to move "$1".',
'errCopyInItself' : 'Unable to copy "$1" into itself.',
'errRm' : 'Unable to remove "$1".',
'errTrash' : 'Unable into trash.', // from v2.1.24 added 30.4.2017
'errRmSrc' : 'Unable remove source file(s).',
'errExtract' : 'Unable to extract files from "$1".',
'errArchive' : 'Unable to create archive.',
'errArcType' : 'Unsupported archive type.',
'errNoArchive' : 'File is not archive or has unsupported archive type.',
'errCmdNoSupport' : 'Backend does not support this command.',
'errReplByChild' : 'The folder "$1" can\'t be replaced by an item it contains.',
'errArcSymlinks' : 'For security reason denied to unpack archives contains symlinks or files with not allowed names.', // edited 24.06.2012
'errArcMaxSize' : 'Archive files exceeds maximum allowed size.',
'errResize' : 'Unable to resize "$1".',
'errResizeDegree' : 'Invalid rotate degree.', // added 7.3.2013
'errResizeRotate' : 'Unable to rotate image.', // added 7.3.2013
'errResizeSize' : 'Invalid image size.', // added 7.3.2013
'errResizeNoChange' : 'Image size not changed.', // added 7.3.2013
'errUsupportType' : 'Unsupported file type.',
'errNotUTF8Content' : 'File "$1" is not in UTF-8 and cannot be edited.', // added 9.11.2011
'errNetMount' : 'Unable to mount "$1".', // added 17.04.2012
'errNetMountNoDriver' : 'Unsupported protocol.', // added 17.04.2012
'errNetMountFailed' : 'Mount failed.', // added 17.04.2012
'errNetMountHostReq' : 'Host required.', // added 18.04.2012
'errSessionExpires' : 'Your session has expired due to inactivity.',
'errCreatingTempDir' : 'Unable to create temporary directory: "$1"',
'errFtpDownloadFile' : 'Unable to download file from FTP: "$1"',
'errFtpUploadFile' : 'Unable to upload file to FTP: "$1"',
'errFtpMkdir' : 'Unable to create remote directory on FTP: "$1"',
'errArchiveExec' : 'Error while archiving files: "$1"',
'errExtractExec' : 'Error while extracting files: "$1"',
'errNetUnMount' : 'Unable to unmount.', // from v2.1 added 30.04.2012
'errConvUTF8' : 'Not convertible to UTF-8', // from v2.1 added 08.04.2014
'errFolderUpload' : 'Try the modern browser, If you\'d like to upload the folder.', // from v2.1 added 26.6.2015
'errSearchTimeout' : 'Timed out while searching "$1". Search result is partial.', // from v2.1 added 12.1.2016
'errReauthRequire' : 'Re-authorization is required.', // from v2.1.10 added 24.3.2016
'errMaxTargets' : 'Max number of selectable items is $1.', // from v2.1.17 added 17.10.2016
'errRestore' : 'Unable to restore from the trash. Can\'t identify the restore destination.', // from v2.1.24 added 3.5.2017
'errEditorNotFound' : 'Editor not found to this file type.', // from v2.1.25 added 23.5.2017
'errServerError' : 'Error occurred on the server side.', // from v2.1.25 added 16.6.2017
'errEmpty' : 'Unable to empty folder "$1".', // from v2.1.25 added 22.6.2017
/******************************* commands names ********************************/
'cmdarchive' : 'Create archive',
'cmdback' : 'Back',
'cmdcopy' : 'Copy',
'cmdcut' : 'Cut',
'cmddownload' : 'Download',
'cmdduplicate' : 'Duplicate',
'cmdedit' : 'Edit file',
'cmdextract' : 'Extract files from archive',
'cmdforward' : 'Forward',
'cmdgetfile' : 'Select files',
'cmdhelp' : 'About this software',
'cmdhome' : 'Root',
'cmdinfo' : 'Get info',
'cmdmkdir' : 'New folder',
'cmdmkdirin' : 'Into New Folder', // from v2.1.7 added 19.2.2016
'cmdmkfile' : 'New file',
'cmdopen' : 'Open',
'cmdpaste' : 'Paste',
'cmdquicklook' : 'Preview',
'cmdreload' : 'Reload',
'cmdrename' : 'Rename',
'cmdrm' : 'Delete',
'cmdtrash' : 'Into trash', //from v2.1.24 added 29.4.2017
'cmdrestore' : 'Restore', //from v2.1.24 added 3.5.2017
'cmdsearch' : 'Find files',
'cmdup' : 'Go to parent folder',
'cmdupload' : 'Upload files',
'cmdview' : 'View',
'cmdresize' : 'Resize & Rotate',
'cmdsort' : 'Sort',
'cmdnetmount' : 'Mount network volume', // added 18.04.2012
'cmdnetunmount': 'Unmount', // from v2.1 added 30.04.2012
'cmdplaces' : 'To Places', // added 28.12.2014
'cmdchmod' : 'Change mode', // from v2.1 added 20.6.2015
'cmdopendir' : 'Open a folder', // from v2.1 added 13.1.2016
'cmdcolwidth' : 'Reset column width', // from v2.1.13 added 12.06.2016
'cmdfullscreen': 'Full Screen', // from v2.1.15 added 03.08.2016
'cmdmove' : 'Move', // from v2.1.15 added 21.08.2016
'cmdempty' : 'Empty the folder', // from v2.1.25 added 22.06.2017
'cmdundo' : 'Undo', // from v2.1.27 added 31.07.2017
'cmdredo' : 'Redo', // from v2.1.27 added 31.07.2017
'cmdpreference': 'Preferences', // from v2.1.27 added 03.08.2017
'cmdselectall' : 'Select all', // from v2.1.28 added 15.08.2017
'cmdselectnone': 'Select none', // from v2.1.28 added 15.08.2017
'cmdselectinvert': 'Invert selection', // from v2.1.28 added 15.08.2017
'cmdopennew' : 'Open in new window', // from v2.1.38 added 3.4.2018
'cmdhide' : 'Hide (Preference)', // from v2.1.41 added 24.7.2018
/*********************************** buttons ***********************************/
'btnClose' : 'Close',
'btnSave' : 'Save',
'btnRm' : 'Remove',
'btnApply' : 'Apply',
'btnCancel' : 'Cancel',
'btnNo' : 'No',
'btnYes' : 'Yes',
'btnMount' : 'Mount', // added 18.04.2012
'btnApprove': 'Goto $1 & approve', // from v2.1 added 26.04.2012
'btnUnmount': 'Unmount', // from v2.1 added 30.04.2012
'btnConv' : 'Convert', // from v2.1 added 08.04.2014
'btnCwd' : 'Here', // from v2.1 added 22.5.2015
'btnVolume' : 'Volume', // from v2.1 added 22.5.2015
'btnAll' : 'All', // from v2.1 added 22.5.2015
'btnMime' : 'MIME Type', // from v2.1 added 22.5.2015
'btnFileName':'Filename', // from v2.1 added 22.5.2015
'btnSaveClose': 'Save & Close', // from v2.1 added 12.6.2015
'btnBackup' : 'Backup', // fromv2.1 added 28.11.2015
'btnRename' : 'Rename', // from v2.1.24 added 6.4.2017
'btnRenameAll' : 'Rename(All)', // from v2.1.24 added 6.4.2017
'btnPrevious' : 'Prev ($1/$2)', // from v2.1.24 added 11.5.2017
'btnNext' : 'Next ($1/$2)', // from v2.1.24 added 11.5.2017
'btnSaveAs' : 'Save As', // from v2.1.25 added 24.5.2017
/******************************** notifications ********************************/
'ntfopen' : 'Open folder',
'ntffile' : 'Open file',
'ntfreload' : 'Reload folder content',
'ntfmkdir' : 'Creating folder',
'ntfmkfile' : 'Creating files',
'ntfrm' : 'Delete items',
'ntfcopy' : 'Copy items',
'ntfmove' : 'Move items',
'ntfprepare' : 'Checking existing items',
'ntfrename' : 'Rename files',
'ntfupload' : 'Uploading files',
'ntfdownload' : 'Downloading files',
'ntfsave' : 'Save files',
'ntfarchive' : 'Creating archive',
'ntfextract' : 'Extracting files from archive',
'ntfsearch' : 'Searching files',
'ntfresize' : 'Resizing images',
'ntfsmth' : 'Doing something',
'ntfloadimg' : 'Loading image',
'ntfnetmount' : 'Mounting network volume', // added 18.04.2012
'ntfnetunmount': 'Unmounting network volume', // from v2.1 added 30.04.2012
'ntfdim' : 'Acquiring image dimension', // added 20.05.2013
'ntfreaddir' : 'Reading folder infomation', // from v2.1 added 01.07.2013
'ntfurl' : 'Getting URL of link', // from v2.1 added 11.03.2014
'ntfchmod' : 'Changing file mode', // from v2.1 added 20.6.2015
'ntfpreupload': 'Verifying upload file name', // from v2.1 added 31.11.2015
'ntfzipdl' : 'Creating a file for download', // from v2.1.7 added 23.1.2016
'ntfparents' : 'Getting path infomation', // from v2.1.17 added 2.11.2016
'ntfchunkmerge': 'Processing the uploaded file', // from v2.1.17 added 2.11.2016
'ntftrash' : 'Doing throw in the trash', // from v2.1.24 added 2.5.2017
'ntfrestore' : 'Doing restore from the trash', // from v2.1.24 added 3.5.2017
'ntfchkdir' : 'Checking destination folder', // from v2.1.24 added 3.5.2017
'ntfundo' : 'Undoing previous operation', // from v2.1.27 added 31.07.2017
'ntfredo' : 'Redoing previous undone', // from v2.1.27 added 31.07.2017
'ntfchkcontent' : 'Checking contents', // from v2.1.41 added 3.8.2018
/*********************************** volumes *********************************/
'volume_Trash' : 'Trash', //from v2.1.24 added 29.4.2017
/************************************ dates **********************************/
'dateUnknown' : 'unknown',
'Today' : 'Today',
'Yesterday' : 'Yesterday',
'msJan' : 'Jan',
'msFeb' : 'Feb',
'msMar' : 'Mar',
'msApr' : 'Apr',
'msMay' : 'May',
'msJun' : 'Jun',
'msJul' : 'Jul',
'msAug' : 'Aug',
'msSep' : 'Sep',
'msOct' : 'Oct',
'msNov' : 'Nov',
'msDec' : 'Dec',
'January' : 'January',
'February' : 'February',
'March' : 'March',
'April' : 'April',
'May' : 'May',
'June' : 'June',
'July' : 'July',
'August' : 'August',
'September' : 'September',
'October' : 'October',
'November' : 'November',
'December' : 'December',
'Sunday' : 'Sunday',
'Monday' : 'Monday',
'Tuesday' : 'Tuesday',
'Wednesday' : 'Wednesday',
'Thursday' : 'Thursday',
'Friday' : 'Friday',
'Saturday' : 'Saturday',
'Sun' : 'Sun',
'Mon' : 'Mon',
'Tue' : 'Tue',
'Wed' : 'Wed',
'Thu' : 'Thu',
'Fri' : 'Fri',
'Sat' : 'Sat',
/******************************** sort variants ********************************/
'sortname' : 'by name',
'sortkind' : 'by kind',
'sortsize' : 'by size',
'sortdate' : 'by date',
'sortFoldersFirst' : 'Folders first',
'sortperm' : 'by permission', // from v2.1.13 added 13.06.2016
'sortmode' : 'by mode', // from v2.1.13 added 13.06.2016
'sortowner' : 'by owner', // from v2.1.13 added 13.06.2016
'sortgroup' : 'by group', // from v2.1.13 added 13.06.2016
'sortAlsoTreeview' : 'Also Treeview', // from v2.1.15 added 01.08.2016
/********************************** new items **********************************/
'untitled file.txt' : 'NewFile.txt', // added 10.11.2015
'untitled folder' : 'NewFolder', // added 10.11.2015
'Archive' : 'NewArchive', // from v2.1 added 10.11.2015
'untitled file' : 'NewFile.$1', // from v2.1.41 added 6.8.2018
'extentionfile' : '$1: File', // from v2.1.41 added 6.8.2018
'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018
/********************************** messages **********************************/
'confirmReq' : 'Confirmation required',
'confirmRm' : 'Are you sure you want to permanently remove items?<br/>This cannot be undone!',
'confirmRepl' : 'Replace old file with new one? (If it contains folders, it will be merged. To backup and replace, select Backup.)',
'confirmRest' : 'Replace existing item with the item in trash?', // fromv2.1.24 added 5.5.2017
'confirmConvUTF8' : 'Not in UTF-8<br/>Convert to UTF-8?<br/>Contents become UTF-8 by saving after conversion.', // from v2.1 added 08.04.2014
'confirmNonUTF8' : 'Character encoding of this file couldn\'t be detected. It need to temporarily convert to UTF-8 for editting.<br/>Please select character encoding of this file.', // from v2.1.19 added 28.11.2016
'confirmNotSave' : 'It has been modified.<br/>Losing work if you do not save changes.', // from v2.1 added 15.7.2015
'confirmTrash' : 'Are you sure you want to move items to trash bin?', //from v2.1.24 added 29.4.2017
'apllyAll' : 'Apply to all',
'name' : 'Name',
'size' : 'Size',
'perms' : 'Permissions',
'modify' : 'Modified',
'kind' : 'Kind',
'read' : 'read',
'write' : 'write',
'noaccess' : 'no access',
'and' : 'and',
'unknown' : 'unknown',
'selectall' : 'Select all items',
'selectfiles' : 'Select item(s)',
'selectffile' : 'Select first item',
'selectlfile' : 'Select last item',
'viewlist' : 'List view',
'viewicons' : 'Icons view',
'viewSmall' : 'Small icons', // from v2.1.39 added 22.5.2018
'viewMedium' : 'Medium icons', // from v2.1.39 added 22.5.2018
'viewLarge' : 'Large icons', // from v2.1.39 added 22.5.2018
'viewExtraLarge' : 'Extra large icons', // from v2.1.39 added 22.5.2018
'places' : 'Places',
'calc' : 'Calculate',
'path' : 'Path',
'aliasfor' : 'Alias for',
'locked' : 'Locked',
'dim' : 'Dimensions',
'files' : 'Files',
'folders' : 'Folders',
'items' : 'Items',
'yes' : 'yes',
'no' : 'no',
'link' : 'Link',
'searcresult' : 'Search results',
'selected' : 'selected items',
'about' : 'About',
'shortcuts' : 'Shortcuts',
'help' : 'Help',
'webfm' : 'Web file manager',
'ver' : 'Version',
'protocolver' : 'protocol version',
'homepage' : 'Project home',
'docs' : 'Documentation',
'github' : 'Fork us on GitHub',
'twitter' : 'Follow us on Twitter',
'facebook' : 'Join us on Facebook',
'team' : 'Team',
'chiefdev' : 'chief developer',
'developer' : 'developer',
'contributor' : 'contributor',
'maintainer' : 'maintainer',
'translator' : 'translator',
'icons' : 'Icons',
'dontforget' : 'and don\'t forget to take your towel',
'shortcutsof' : 'Shortcuts disabled',
'dropFiles' : 'Drop files here',
'or' : 'or',
'selectForUpload' : 'Select files',
'moveFiles' : 'Move items',
'copyFiles' : 'Copy items',
'restoreFiles' : 'Restore items', // from v2.1.24 added 5.5.2017
'rmFromPlaces' : 'Remove from places',
'aspectRatio' : 'Aspect ratio',
'scale' : 'Scale',
'width' : 'Width',
'height' : 'Height',
'resize' : 'Resize',
'crop' : 'Crop',
'rotate' : 'Rotate',
'rotate-cw' : 'Rotate 90 degrees CW',
'rotate-ccw' : 'Rotate 90 degrees CCW',
'degree' : '°',
'netMountDialogTitle' : 'Mount network volume', // added 18.04.2012
'protocol' : 'Protocol', // added 18.04.2012
'host' : 'Host', // added 18.04.2012
'port' : 'Port', // added 18.04.2012
'user' : 'User', // added 18.04.2012
'pass' : 'Password', // added 18.04.2012
'confirmUnmount' : 'Are you sure to unmount $1?', // from v2.1 added 30.04.2012
'dropFilesBrowser': 'Drop or Paste files from browser', // from v2.1 added 30.05.2012
'dropPasteFiles' : 'Drop files, Paste URLs or images(clipboard) here', // from v2.1 added 07.04.2014
'encoding' : 'Encoding', // from v2.1 added 19.12.2014
'locale' : 'Locale', // from v2.1 added 19.12.2014
'searchTarget' : 'Target: $1', // from v2.1 added 22.5.2015
'searchMime' : 'Search by input MIME Type', // from v2.1 added 22.5.2015
'owner' : 'Owner', // from v2.1 added 20.6.2015
'group' : 'Group', // from v2.1 added 20.6.2015
'other' : 'Other', // from v2.1 added 20.6.2015
'execute' : 'Execute', // from v2.1 added 20.6.2015
'perm' : 'Permission', // from v2.1 added 20.6.2015
'mode' : 'Mode', // from v2.1 added 20.6.2015
'emptyFolder' : 'Folder is empty', // from v2.1.6 added 30.12.2015
'emptyFolderDrop' : 'Folder is empty\\A Drop to add items', // from v2.1.6 added 30.12.2015
'emptyFolderLTap' : 'Folder is empty\\A Long tap to add items', // from v2.1.6 added 30.12.2015
'quality' : 'Quality', // from v2.1.6 added 5.1.2016
'autoSync' : 'Auto sync', // from v2.1.6 added 10.1.2016
'moveUp' : 'Move up', // from v2.1.6 added 18.1.2016
'getLink' : 'Get URL link', // from v2.1.7 added 9.2.2016
'selectedItems' : 'Selected items ($1)', // from v2.1.7 added 2.19.2016
'folderId' : 'Folder ID', // from v2.1.10 added 3.25.2016
'offlineAccess' : 'Allow offline access', // from v2.1.10 added 3.25.2016
'reAuth' : 'To re-authenticate', // from v2.1.10 added 3.25.2016
'nowLoading' : 'Now loading...', // from v2.1.12 added 4.26.2016
'openMulti' : 'Open multiple files', // from v2.1.12 added 5.14.2016
'openMultiConfirm': 'You are trying to open the $1 files. Are you sure you want to open in browser?', // from v2.1.12 added 5.14.2016
'emptySearch' : 'Search results is empty in search target.', // from v2.1.12 added 5.16.2016
'editingFile' : 'It is editing a file.', // from v2.1.13 added 6.3.2016
'hasSelected' : 'You have selected $1 items.', // from v2.1.13 added 6.3.2016
'hasClipboard' : 'You have $1 items in the clipboard.', // from v2.1.13 added 6.3.2016
'incSearchOnly' : 'Incremental search is only from the current view.', // from v2.1.13 added 6.30.2016
'reinstate' : 'Reinstate', // from v2.1.15 added 3.8.2016
'complete' : '$1 complete', // from v2.1.15 added 21.8.2016
'contextmenu' : 'Context menu', // from v2.1.15 added 9.9.2016
'pageTurning' : 'Page turning', // from v2.1.15 added 10.9.2016
'volumeRoots' : 'Volume roots', // from v2.1.16 added 16.9.2016
'reset' : 'Reset', // from v2.1.16 added 1.10.2016
'bgcolor' : 'Background color', // from v2.1.16 added 1.10.2016
'colorPicker' : 'Color picker', // from v2.1.16 added 1.10.2016
'8pxgrid' : '8px Grid', // from v2.1.16 added 4.10.2016
'enabled' : 'Enabled', // from v2.1.16 added 4.10.2016
'disabled' : 'Disabled', // from v2.1.16 added 4.10.2016
'emptyIncSearch' : 'Search results is empty in current view.\\A Press [Enter] to expand search target.', // from v2.1.16 added 5.10.2016
'emptyLetSearch' : 'First letter search results is empty in current view.', // from v2.1.23 added 24.3.2017
'textLabel' : 'Text label', // from v2.1.17 added 13.10.2016
'minsLeft' : '$1 mins left', // from v2.1.17 added 13.11.2016
'openAsEncoding' : 'Reopen with selected encoding', // from v2.1.19 added 2.12.2016
'saveAsEncoding' : 'Save with the selected encoding', // from v2.1.19 added 2.12.2016
'selectFolder' : 'Select folder', // from v2.1.20 added 13.12.2016
'firstLetterSearch': 'First letter search', // from v2.1.23 added 24.3.2017
'presets' : 'Presets', // from v2.1.25 added 26.5.2017
'tooManyToTrash' : 'It\'s too many items so it can\'t into trash.', // from v2.1.25 added 9.6.2017
'TextArea' : 'TextArea', // from v2.1.25 added 14.6.2017
'folderToEmpty' : 'Empty the folder "$1".', // from v2.1.25 added 22.6.2017
'filderIsEmpty' : 'There are no items in a folder "$1".', // from v2.1.25 added 22.6.2017
'preference' : 'Preference', // from v2.1.26 added 28.6.2017
'language' : 'Language', // from v2.1.26 added 28.6.2017
'clearBrowserData': 'Initialize the settings saved in this browser', // from v2.1.26 added 28.6.2017
'toolbarPref' : 'Toolbar settings', // from v2.1.27 added 2.8.2017
'charsLeft' : '... $1 chars left.', // from v2.1.29 added 30.8.2017
'sum' : 'Sum', // from v2.1.29 added 28.9.2017
'roughFileSize' : 'Rough file size', // from v2.1.30 added 2.11.2017
'autoFocusDialog' : 'Focus on the element of dialog with mouseover', // from v2.1.30 added 2.11.2017
'select' : 'Select', // from v2.1.30 added 23.11.2017
'selectAction' : 'Action when select file', // from v2.1.30 added 23.11.2017
'useStoredEditor' : 'Open with the editor used last time', // from v2.1.30 added 23.11.2017
'selectinvert' : 'Invert selection', // from v2.1.30 added 25.11.2017
'renameMultiple' : 'Are you sure you want to rename $1 selected items like $2?<br/>This cannot be undone!', // from v2.1.31 added 4.12.2017
'batchRename' : 'Batch rename', // from v2.1.31 added 8.12.2017
'plusNumber' : '+ Number', // from v2.1.31 added 8.12.2017
'asPrefix' : 'Add prefix', // from v2.1.31 added 8.12.2017
'asSuffix' : 'Add suffix', // from v2.1.31 added 8.12.2017
'changeExtention' : 'Change extention', // from v2.1.31 added 8.12.2017
'columnPref' : 'Columns settings (List view)', // from v2.1.32 added 6.2.2018
'reflectOnImmediate' : 'All changes will reflect immediately to the archive.', // from v2.1.33 added 2.3.2018
'reflectOnUnmount' : 'Any changes will not reflect until un-mount this volume.', // from v2.1.33 added 2.3.2018
'unmountChildren' : 'The following volume(s) mounted on this volume also unmounted. Are you sure to unmount it?', // from v2.1.33 added 5.3.2018
'selectionInfo' : 'Selection Info', // from v2.1.33 added 7.3.2018
'hashChecker' : 'Algorithms to show the file hash', // from v2.1.33 added 10.3.2018
'infoItems' : 'Info Items (Selection Info Panel)', // from v2.1.38 added 28.3.2018
'pressAgainToExit': 'Press again to exit.', // from v2.1.38 added 1.4.2018
'toolbar' : 'Toolbar', // from v2.1.38 added 4.4.2018
'workspace' : 'Work Space', // from v2.1.38 added 4.4.2018
'dialog' : 'Dialog', // from v2.1.38 added 4.4.2018
'all' : 'All', // from v2.1.38 added 4.4.2018
'iconSize' : 'Icon Size (Icons view)', // from v2.1.39 added 7.5.2018
'editorMaximized' : 'Open the maximized editor window', // from v2.1.40 added 30.6.2018
'editorConvNoApi' : 'Because conversion by API is not currently available, please convert on the website.', //from v2.1.40 added 8.7.2018
'editorConvNeedUpload' : 'After conversion, you must be upload with the item URL or a downloaded file to save the converted file.', //from v2.1.40 added 8.7.2018
'convertOn' : 'Convert on the site of $1', // from v2.1.40 added 10.7.2018
'integrations' : 'Integrations', // from v2.1.40 added 11.7.2018
'integrationWith' : 'This elFinder has the following external services integrated. Please check the terms of use, privacy policy, etc. before using it.', // from v2.1.40 added 11.7.2018
'showHidden' : 'Show hidden items', // from v2.1.41 added 24.7.2018
'hideHidden' : 'Hide hidden items', // from v2.1.41 added 24.7.2018
'toggleHidden' : 'Show/Hide hidden items', // from v2.1.41 added 24.7.2018
'makefileTypes' : 'File types to enable with "New file"', // from v2.1.41 added 7.8.2018
'typeOfTextfile' : 'Type of the Text file', // from v2.1.41 added 7.8.2018
'add' : 'Add', // from v2.1.41 added 7.8.2018
'theme' : 'Theme', // from v2.1.43 added 19.10.2018
'default' : 'Default', // from v2.1.43 added 19.10.2018
'description' : 'Description', // from v2.1.43 added 19.10.2018
'website' : 'Website', // from v2.1.43 added 19.10.2018
'author' : 'Author', // from v2.1.43 added 19.10.2018
'email' : 'Email', // from v2.1.43 added 19.10.2018
'license' : 'License', // from v2.1.43 added 19.10.2018
/********************************** mimetypes **********************************/
'kindUnknown' : 'Unknown',
'kindRoot' : 'Volume Root', // from v2.1.16 added 16.10.2016
'kindFolder' : 'Folder',
'kindSelects' : 'Selections', // from v2.1.29 added 29.8.2017
'kindAlias' : 'Alias',
'kindAliasBroken' : 'Broken alias',
// applications
'kindApp' : 'Application',
'kindPostscript' : 'Postscript document',
'kindMsOffice' : 'Microsoft Office document',
'kindMsWord' : 'Microsoft Word document',
'kindMsExcel' : 'Microsoft Excel document',
'kindMsPP' : 'Microsoft Powerpoint presentation',
'kindOO' : 'Open Office document',
'kindAppFlash' : 'Flash application',
'kindPDF' : 'Portable Document Format (PDF)',
'kindTorrent' : 'Bittorrent file',
'kind7z' : '7z archive',
'kindTAR' : 'TAR archive',
'kindGZIP' : 'GZIP archive',
'kindBZIP' : 'BZIP archive',
'kindXZ' : 'XZ archive',
'kindZIP' : 'ZIP archive',
'kindRAR' : 'RAR archive',
'kindJAR' : 'Java JAR file',
'kindTTF' : 'True Type font',
'kindOTF' : 'Open Type font',
'kindRPM' : 'RPM package',
// texts
'kindText' : 'Text document',
'kindTextPlain' : 'Plain text',
'kindPHP' : 'PHP source',
'kindCSS' : 'Cascading style sheet',
'kindHTML' : 'HTML document',
'kindJS' : 'Javascript source',
'kindRTF' : 'Rich Text Format',
'kindC' : 'C source',
'kindCHeader' : 'C header source',
'kindCPP' : 'C++ source',
'kindCPPHeader' : 'C++ header source',
'kindShell' : 'Unix shell script',
'kindPython' : 'Python source',
'kindJava' : 'Java source',
'kindRuby' : 'Ruby source',
'kindPerl' : 'Perl script',
'kindSQL' : 'SQL source',
'kindXML' : 'XML document',
'kindAWK' : 'AWK source',
'kindCSV' : 'Comma separated values',
'kindDOCBOOK' : 'Docbook XML document',
'kindMarkdown' : 'Markdown text', // added 20.7.2015
// images
'kindImage' : 'Image',
'kindBMP' : 'BMP image',
'kindJPEG' : 'JPEG image',
'kindGIF' : 'GIF Image',
'kindPNG' : 'PNG Image',
'kindTIFF' : 'TIFF image',
'kindTGA' : 'TGA image',
'kindPSD' : 'Adobe Photoshop image',
'kindXBITMAP' : 'X bitmap image',
'kindPXM' : 'Pixelmator image',
// media
'kindAudio' : 'Audio media',
'kindAudioMPEG' : 'MPEG audio',
'kindAudioMPEG4' : 'MPEG-4 audio',
'kindAudioMIDI' : 'MIDI audio',
'kindAudioOGG' : 'Ogg Vorbis audio',
'kindAudioWAV' : 'WAV audio',
'AudioPlaylist' : 'MP3 playlist',
'kindVideo' : 'Video media',
'kindVideoDV' : 'DV movie',
'kindVideoMPEG' : 'MPEG movie',
'kindVideoMPEG4' : 'MPEG-4 movie',
'kindVideoAVI' : 'AVI movie',
'kindVideoMOV' : 'Quick Time movie',
'kindVideoWM' : 'Windows Media movie',
'kindVideoFlash' : 'Flash movie',
'kindVideoMKV' : 'Matroska movie',
'kindVideoOGG' : 'Ogg movie'
}
};
}
/*
* File: /js/ui/button.js
*/
/**
* @class elFinder toolbar button widget.
* If command has variants - create menu
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfinderbutton = function(cmd) {
return this.each(function() {
var c = 'class',
fm = cmd.fm,
disabled = fm.res(c, 'disabled'),
active = fm.res(c, 'active'),
hover = fm.res(c, 'hover'),
item = 'elfinder-button-menu-item',
selected = 'elfinder-button-menu-item-selected',
menu,
text = $('<span class="elfinder-button-text">'+cmd.title+'</span>'),
prvCname = 'elfinder-button-icon-' + (cmd.className? cmd.className : cmd.name),
button = $(this).addClass('ui-state-default elfinder-button')
.attr('title', cmd.title)
.append('<span class="elfinder-button-icon ' + prvCname + '"/>', text)
.on('mouseenter mouseleave', function(e) { !button.hasClass(disabled) && button[e.type == 'mouseleave' ? 'removeClass' : 'addClass'](hover);})
.on('click', function(e) {
if (!button.hasClass(disabled)) {
if (menu && cmd.variants.length >= 1) {
// close other menus
menu.is(':hidden') && fm.getUI().click();
e.stopPropagation();
menu.css(getMenuOffset()).slideToggle({
duration: 100,
done: function(e) {
fm[menu.is(':visible')? 'toFront' : 'toHide'](menu);
}
});
} else {
fm.exec(cmd.name, getSelected(), {_userAction: true, _currentType: 'toolbar', _currentNode: button });
}
}
}),
hideMenu = function() {
fm.toHide(menu);
},
getMenuOffset = function() {
var fmNode = fm.getUI(),
baseOffset = fm.getUI().offset(),
buttonOffset = fmNode.offset();
return {
top : buttonOffset.top - baseOffset.top,
left : buttonOffset.left - baseOffset.left,
maxHeight : fmNode.height() - 40
};
},
getSelected = function() {
var sel = fm.selected(),
cwd;
if (!sel.length) {
if (cwd = fm.cwd()) {
sel = [ fm.cwd().hash ];
} else {
sel = void(0);
}
}
return sel;
},
tm;
text.hide();
// set self button object to cmd object
cmd.button = button;
// if command has variants create menu
if (Array.isArray(cmd.variants)) {
button.addClass('elfinder-menubutton');
menu = $('<div class="ui-front ui-widget ui-widget-content elfinder-button-menu ui-corner-all"/>')
.hide()
.appendTo(fm.getUI())
.on('mouseenter mouseleave', '.'+item, function() { $(this).toggleClass(hover); })
.on('click', '.'+item, function(e) {
var opts = $(this).data('value');
e.preventDefault();
e.stopPropagation();
button.removeClass(hover);
fm.toHide(menu);
if (typeof opts === 'undefined') {
opts = {};
}
if (typeof opts === 'object') {
opts._userAction = true;
}
fm.exec(cmd.name, getSelected(), opts);
})
.on('close', hideMenu);
fm.bind('disable select', hideMenu).getUI().on('click', hideMenu);
cmd.change(function() {
menu.html('');
$.each(cmd.variants, function(i, variant) {
menu.append($('<div class="'+item+'">'+variant[1]+'</div>').data('value', variant[0]).addClass(variant[0] == cmd.value ? selected : ''));
});
});
}
cmd.change(function() {
var cName;
tm && cancelAnimationFrame(tm);
tm = requestAnimationFrame(function() {
if (cmd.disabled()) {
button.removeClass(active+' '+hover).addClass(disabled);
} else {
button.removeClass(disabled);
button[cmd.active() ? 'addClass' : 'removeClass'](active);
}
if (cmd.syncTitleOnChange) {
cName = 'elfinder-button-icon-' + (cmd.className? cmd.className : cmd.name);
if (prvCname !== cName) {
button.children('.elfinder-button-icon').removeClass(prvCname).addClass(cName);
prvCname = cName;
}
text.html(cmd.title);
button.attr('title', cmd.title);
}
});
})
.change();
});
};
/*
* File: /js/ui/contextmenu.js
*/
/**
* @class elFinder contextmenu
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfindercontextmenu = function(fm) {
return this.each(function() {
var self = $(this),
cmItem = 'elfinder-contextmenu-item',
smItem = 'elfinder-contextsubmenu-item',
exIcon = 'elfinder-contextmenu-extra-icon',
cHover = fm.res('class', 'hover'),
dragOpt = {
distance: 8,
start: function() {
menu.data('drag', true).data('touching') && menu.find('.'+cHover).removeClass(cHover);
},
stop: function() {
menu.data('draged', true).removeData('drag');
}
},
menu = $(this).addClass('touch-punch ui-helper-reset ui-front ui-widget ui-state-default ui-corner-all elfinder-contextmenu elfinder-contextmenu-'+fm.direction)
.hide()
.on('touchstart', function(e) {
menu.data('touching', true).children().removeClass(cHover);
})
.on('touchend', function(e) {
menu.removeData('touching');
})
.on('mouseenter mouseleave', '.'+cmItem, function(e) {
$(this).toggleClass(cHover, (e.type === 'mouseenter' || (! menu.data('draged') && menu.data('submenuKeep'))? true : false));
if (menu.data('draged') && menu.data('submenuKeep')) {
menu.find('.elfinder-contextmenu-sub:visible').parent().addClass(cHover);
}
})
.on('mouseenter mouseleave', '.'+exIcon, function(e) {
$(this).parent().toggleClass(cHover, e.type === 'mouseleave');
})
.on('mouseenter mouseleave', '.'+cmItem+',.'+smItem, function(e) {
var setIndex = function(target, sub) {
$.each(sub? subnodes : nodes, function(i, n) {
if (target[0] === n) {
(sub? subnodes : nodes)._cur = i;
if (sub) {
subselected = target;
} else {
selected = target;
}
return false;
}
});
};
if (e.originalEvent) {
var target = $(this),
unHover = function() {
if (selected && !selected.children('div.elfinder-contextmenu-sub:visible').length) {
selected.removeClass(cHover);
}
};
if (e.type === 'mouseenter') {
// mouseenter
if (target.hasClass(smItem)) {
// submenu
if (subselected) {
subselected.removeClass(cHover);
}
if (selected) {
subnodes = selected.find('div.'+smItem);
}
setIndex(target, true);
} else {
// menu
unHover();
setIndex(target);
}
} else {
// mouseleave
if (target.hasClass(smItem)) {
//submenu
subselected = null;
subnodes = null;
} else {
// menu
unHover();
(function(sel) {
setTimeout(function() {
if (sel === selected) {
selected = null;
}
}, 250);
})(selected);
}
}
}
})
.on('contextmenu', function(){return false;})
.on('mouseup', function() {
setTimeout(function() {
menu.removeData('draged');
}, 100);
})
.draggable(dragOpt),
ltr = fm.direction === 'ltr',
subpos = ltr? 'left' : 'right',
types = Object.assign({}, fm.options.contextmenu),
tpl = '<div class="'+cmItem+'{className}"><span class="elfinder-button-icon {icon} elfinder-contextmenu-icon"{style}/><span>{label}</span></div>',
item = function(label, icon, callback, opts) {
var className = '',
style = '',
iconClass = '',
v, pos;
if (opts) {
if (opts.className) {
className = ' ' + opts.className;
}
if (opts.iconClass) {
iconClass = opts.iconClass;
icon = '';
}
if (opts.iconImg) {
v = opts.iconImg.split(/ +/);
pos = v[1] && v[2]? fm.escape(v[1] + 'px ' + v[2] + 'px') : '';
style = ' style="background:url(\''+fm.escape(v[0])+'\') '+(pos? pos : '0 0')+' no-repeat;'+(pos? '' : 'posbackground-size:contain;')+'"';
}
}
return $(tpl.replace('{icon}', icon ? 'elfinder-button-icon-'+icon : (iconClass? iconClass : ''))
.replace('{label}', label)
.replace('{style}', style)
.replace('{className}', className))
.on('click', function(e) {
e.stopPropagation();
e.preventDefault();
callback();
});
},
urlIcon = function(iconUrl) {
var v = iconUrl.split(/ +/),
pos = v[1] && v[2]? (v[1] + 'px ' + v[2] + 'px') : '';
return {
backgroundImage: 'url("'+v[0]+'")',
backgroundRepeat: 'no-repeat',
backgroundPosition: pos? pos : '',
backgroundSize: pos? '' : 'contain'
};
},
base, cwd,
nodes, selected, subnodes, subselected, autoSyncStop, subHoverTm,
autoToggle = function() {
var evTouchStart = 'touchstart.contextmenuAutoToggle';
menu.data('hideTm') && clearTimeout(menu.data('hideTm'));
if (menu.is(':visible')) {
menu.on('touchstart', function(e) {
if (e.originalEvent.touches.length > 1) {
return;
}
menu.stop();
fm.toFront(menu);
menu.data('hideTm') && clearTimeout(menu.data('hideTm'));
})
.data('hideTm', setTimeout(function() {
if (menu.is(':visible')) {
cwd.find('.elfinder-cwd-file').off(evTouchStart);
cwd.find('.elfinder-cwd-file.ui-selected')
.one(evTouchStart, function(e) {
if (e.originalEvent.touches.length > 1) {
return;
}
var tgt = $(e.target);
if (menu.first().length && !tgt.is('input:checkbox') && !tgt.hasClass('elfinder-cwd-select')) {
e.stopPropagation();
//e.preventDefault();
open(e.originalEvent.touches[0].pageX, e.originalEvent.touches[0].pageY);
cwd.data('longtap', true)
tgt.one('touchend', function() {
setTimeout(function() {
cwd.removeData('longtap');
}, 80);
});
return;
}
cwd.find('.elfinder-cwd-file').off(evTouchStart);
})
.one('unselect.'+fm.namespace, function() {
cwd.find('.elfinder-cwd-file').off(evTouchStart);
});
menu.fadeOut({
duration: 300,
fail: function() {
menu.css('opacity', '1').show();
},
done: function() {
fm.toHide(menu);
}
});
}
}, 4500));
}
},
keyEvts = function(e) {
var code = e.keyCode,
ESC = $.ui.keyCode.ESCAPE,
ENT = $.ui.keyCode.ENTER,
LEFT = $.ui.keyCode.LEFT,
RIGHT = $.ui.keyCode.RIGHT,
UP = $.ui.keyCode.UP,
DOWN = $.ui.keyCode.DOWN,
subent = fm.direction === 'ltr'? RIGHT : LEFT,
sublev = subent === RIGHT? LEFT : RIGHT;
if ($.inArray(code, [ESC, ENT, LEFT, RIGHT, UP, DOWN]) !== -1) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
if (code == ESC || code === sublev) {
if (selected && subnodes && subselected) {
subselected.trigger('mouseleave').trigger('submenuclose');
selected.addClass(cHover);
subnodes = null;
subselected = null;
} else {
code == ESC && close();
}
} else if (code == UP || code == DOWN) {
if (subnodes) {
if (subselected) {
subselected.trigger('mouseleave');
}
if (code == DOWN && (! subselected || subnodes.length <= ++subnodes._cur)) {
subnodes._cur = 0;
} else if (code == UP && (! subselected || --subnodes._cur < 0)) {
subnodes._cur = subnodes.length - 1;
}
subselected = subnodes.eq(subnodes._cur).trigger('mouseenter');
} else {
subnodes = null;
if (selected) {
selected.trigger('mouseleave');
}
if (code == DOWN && (! selected || nodes.length <= ++nodes._cur)) {
nodes._cur = 0;
} else if (code == UP && (! selected || --nodes._cur < 0)) {
nodes._cur = nodes.length - 1;
}
selected = nodes.eq(nodes._cur).addClass(cHover);
}
} else if (selected && (code == ENT || code === subent)) {
if (selected.hasClass('elfinder-contextmenu-group')) {
if (subselected) {
code == ENT && subselected.click();
} else {
selected.trigger('mouseenter');
subnodes = selected.find('div.'+smItem);
subnodes._cur = 0;
subselected = subnodes.first().addClass(cHover);
}
} else {
code == ENT && selected.click();
}
}
}
},
open = function(x, y, css) {
var width = menu.outerWidth(),
height = menu.outerHeight(),
bstyle = base.attr('style'),
bpos = base.offset(),
bwidth = base.width(),
bheight = base.height(),
mw = fm.UA.Mobile? 40 : 2,
mh = fm.UA.Mobile? 20 : 2,
x = x - (bpos? bpos.left : 0),
y = y - (bpos? bpos.top : 0),
css = Object.assign(css || {}, {
top : Math.max(0, y + mh + height < bheight ? y + mh : y - (y + height - bheight)),
left : Math.max(0, (x < width + mw || x + mw + width < bwidth)? x + mw : x - mw - width),
opacity : '1'
}),
evts;
autoSyncStop = true;
fm.autoSync('stop');
base.width(bwidth);
menu.stop().removeAttr('style').css(css);
fm.toFront(menu);
menu.show();
base.attr('style', bstyle);
css[subpos] = parseInt(menu.width());
menu.find('.elfinder-contextmenu-sub').css(css);
if (fm.UA.iOS) {
$('div.elfinder div.overflow-scrolling-touch').css('-webkit-overflow-scrolling', 'auto');
}
selected = null;
subnodes = null;
subselected = null;
$(document).on('keydown.' + fm.namespace, keyEvts);
evts = $._data(document).events;
if (evts && evts.keydown) {
evts.keydown.unshift(evts.keydown.pop());
}
fm.UA.Mobile && autoToggle();
requestAnimationFrame(function() {
fm.getUI().one('click.' + fm.namespace, close);
});
},
close = function() {
fm.getUI().off('click.' + fm.namespace, close);
$(document).off('keydown.' + fm.namespace, keyEvts);
currentType = currentTargets = null;
if (menu.is(':visible') || menu.children().length) {
fm.toHide(menu.removeAttr('style').empty().removeData('submenuKeep'));
try {
if (! menu.draggable('instance')) {
menu.draggable(dragOpt);
}
} catch(e) {
if (! menu.hasClass('ui-draggable')) {
menu.draggable(dragOpt);
}
}
if (menu.data('prevNode')) {
menu.data('prevNode').after(menu);
menu.removeData('prevNode');
}
fm.trigger('closecontextmenu');
if (fm.UA.iOS) {
$('div.elfinder div.overflow-scrolling-touch').css('-webkit-overflow-scrolling', 'touch');
}
}
autoSyncStop && fm.searchStatus.state < 1 && ! fm.searchStatus.ininc && fm.autoSync();
autoSyncStop = false;
},
create = function(type, targets) {
var sep = false,
insSep = false,
disabled = [],
isCwd = type === 'cwd',
selcnt = 0,
cmdMap;
currentType = type;
currentTargets = targets;
// get current uiCmdMap option
if (!(cmdMap = fm.option('uiCmdMap', isCwd? void(0) : targets[0]))) {
cmdMap = {};
}
if (!isCwd) {
disabled = fm.getDisabledCmds(targets);
}
selcnt = fm.selected().length;
if (selcnt > 1) {
menu.append('<div class="ui-corner-top ui-widget-header elfinder-contextmenu-header"><span>'
+ fm.i18n('selectedItems', ''+selcnt)
+ '</span></div>');
}
nodes = $();
$.each(types[type]||[], function(i, name) {
var cmd, cmdName, useMap, node, submenu, hover;
if (name === '|') {
if (sep) {
insSep = true;
}
return;
}
if (cmdMap[name]) {
cmdName = cmdMap[name];
useMap = true;
} else {
cmdName = name;
}
cmd = fm.getCommand(cmdName);
if (cmd && !isCwd && (!fm.searchStatus.state || !cmd.disableOnSearch)) {
cmd.__disabled = cmd._disabled;
cmd._disabled = !(cmd.alwaysEnabled || (fm._commands[cmdName] ? $.inArray(name, disabled) === -1 && (!useMap || !disabled[cmdName]) : false));
$.each(cmd.linkedCmds, function(i, n) {
var c;
if (c = fm.getCommand(n)) {
c.__disabled = c._disabled;
c._disabled = !(c.alwaysEnabled || (fm._commands[n] ? !disabled[n] : false));
}
});
}
if (cmd && !cmd._disabled && cmd.getstate(targets) != -1) {
if (cmd.variants) {
if (!cmd.variants.length) {
return;
}
node = item(cmd.title, cmd.className? cmd.className : cmd.name, function(){}, cmd.contextmenuOpts);
submenu = $('<div class="ui-front ui-corner-all elfinder-contextmenu-sub"/>')
.hide()
.css('max-height', fm.getUI().height() - 30)
.appendTo(node.append('<span class="elfinder-contextmenu-arrow"/>'));
hover = function(show){
if (! show) {
submenu.hide();
} else {
var bstyle = base.attr('style');
base.width(base.width());
// top: '-1000px' to prevent visible scrollbar of window with the elFinder option `height: '100%'`
submenu.css({ top: '-1000px', left: 'auto', right: 'auto' });
var nodeOffset = node.offset(),
nodeleft = nodeOffset.left,
nodetop = nodeOffset.top,
nodewidth = node.outerWidth(),
width = submenu.outerWidth(true),
height = submenu.outerHeight(true),
baseOffset = base.offset(),
wwidth = baseOffset.left + base.width(),
wheight = baseOffset.top + base.height(),
cltr = ltr,
x = nodewidth,
y, over;
if (ltr) {
over = (nodeleft + nodewidth + width) - wwidth;
if (over > 10) {
if (nodeleft > width - 5) {
x = x - 5;
cltr = false;
} else {
if (!fm.UA.Mobile) {
x = nodewidth - over;
}
}
}
} else {
over = width - nodeleft;
if (over > 0) {
if ((nodeleft + nodewidth + width - 15) < wwidth) {
x = x - 5;
cltr = true;
} else {
if (!fm.UA.Mobile) {
x = nodewidth - over;
}
}
}
}
over = (nodetop + 5 + height) - wheight;
y = (over > 0 && nodetop < wheight)? 5 - over : (over > 0? 30 - height : 5);
menu.find('.elfinder-contextmenu-sub:visible').hide();
submenu.css({
top : y,
left : cltr? x : 'auto',
right: cltr? 'auto' : x,
overflowY: 'auto'
}).show();
base.attr('style', bstyle);
}
};
node.addClass('elfinder-contextmenu-group')
.on('mouseleave', '.elfinder-contextmenu-sub', function(e) {
if (! menu.data('draged')) {
menu.removeData('submenuKeep');
}
})
.on('submenuclose', '.elfinder-contextmenu-sub', function(e) {
hover(false);
})
.on('click', '.'+smItem, function(e){
var opts, $this;
e.stopPropagation();
if (! menu.data('draged')) {
$this = $(this);
if (!cmd.keepContextmenu) {
menu.hide();
} else {
$this.removeClass(cHover);
node.addClass(cHover);
}
opts = $this.data('exec');
if (typeof opts === 'undefined') {
opts = {};
}
if (typeof opts === 'object') {
opts._userAction = true;
opts._currentType = type;
opts._currentNode = $this;
}
!cmd.keepContextmenu && close();
fm.exec(cmd.name, targets, opts);
}
})
.on('touchend', function(e) {
if (! menu.data('drag')) {
hover(true);
menu.data('submenuKeep', true);
}
})
.on('mouseenter mouseleave', function(e){
if (! menu.data('touching')) {
if (node.data('timer')) {
clearTimeout(node.data('timer'));
node.removeData('timer');
}
if (!$(e.target).closest('.elfinder-contextmenu-sub', menu).length) {
if (e.type === 'mouseleave') {
if (! menu.data('submenuKeep')) {
node.data('timer', setTimeout(function() {
node.removeData('timer');
hover(false);
}, 250));
}
} else {
node.data('timer', setTimeout(function() {
node.removeData('timer');
hover(true);
}, nodes.find('div.elfinder-contextmenu-sub:visible').length? 250 : 0));
}
}
}
});
$.each(cmd.variants, function(i, variant) {
var item = variant === '|' ? '<div class="elfinder-contextmenu-separator"/>' :
$('<div class="'+cmItem+' '+smItem+'"><span>'+variant[1]+'</span></div>').data('exec', variant[0]),
iconClass, icon;
if (typeof variant[2] !== 'undefined') {
icon = $('<span/>').addClass('elfinder-button-icon elfinder-contextmenu-icon');
if (! /\//.test(variant[2])) {
icon.addClass('elfinder-button-icon-'+variant[2]);
} else {
icon.css(urlIcon(variant[2]));
}
item.prepend(icon).addClass(smItem+'-icon');
}
submenu.append(item);
});
} else {
node = item(cmd.title, cmd.className? cmd.className : cmd.name, function() {
if (! menu.data('draged')) {
!cmd.keepContextmenu && close();
fm.exec(cmd.name, targets, {_userAction: true, _currentType: type, _currentNode: node});
}
}, cmd.contextmenuOpts);
if (cmd.extra && cmd.extra.node) {
$('<span class="elfinder-button-icon elfinder-button-icon-'+(cmd.extra.icon || '')+' '+exIcon+'"/>')
.append(cmd.extra.node).appendTo(node);
$(cmd.extra.node).trigger('ready', {targets: targets});
} else {
node.remove('.'+exIcon);
}
}
if (cmd.extendsCmd) {
node.children('span.elfinder-button-icon').addClass('elfinder-button-icon-' + cmd.extendsCmd);
}
if (insSep) {
menu.append('<div class="elfinder-contextmenu-separator"/>');
}
menu.append(node);
sep = true;
insSep = false;
}
if (cmd && typeof cmd.__disabled !== 'undefined') {
cmd._disabled = cmd.__disabled;
delete cmd.__disabled;
$.each(cmd.linkedCmds, function(i, n) {
var c;
if (c = fm.getCommand(n)) {
c._disabled = c.__disabled;
delete c.__disabled;
}
});
}
});
nodes = menu.children('div.'+cmItem);
},
createFromRaw = function(raw) {
currentType = 'raw';
$.each(raw, function(i, data) {
var node;
if (data === '|') {
menu.append('<div class="elfinder-contextmenu-separator"/>');
} else if (data.label && typeof data.callback == 'function') {
node = item(data.label, data.icon, function() {
if (! menu.data('draged')) {
!data.remain && close();
data.callback();
}
}, data.options || null);
menu.append(node);
}
});
nodes = menu.children('div.'+cmItem);
},
currentType = null,
currentTargets = null;
fm.one('load', function() {
base = fm.getUI();
cwd = fm.getUI('cwd');
fm.bind('contextmenu', function(e) {
var data = e.data,
css = {},
prevNode;
if (data.type && data.type !== 'files') {
cwd.trigger('unselectall');
}
close();
if (data.type && data.targets) {
fm.trigger('contextmenucreate', data);
create(data.type, data.targets);
fm.trigger('contextmenucreatedone', data);
} else if (data.raw) {
createFromRaw(data.raw);
}
if (menu.children().length) {
prevNode = data.prevNode || null;
if (prevNode) {
menu.data('prevNode', menu.prev());
prevNode.after(menu);
}
if (data.fitHeight) {
css = {maxHeight: Math.min(fm.getUI().height(), $(window).height()), overflowY: 'auto'};
menu.draggable('destroy').removeClass('ui-draggable');
}
open(data.x, data.y, css);
// call opened callback function
if (data.opened && typeof data.opened === 'function') {
data.opened.call(menu);
}
}
})
.one('destroy', function() { menu.remove(); })
.bind('disable', close)
.bind('select', function(e){
(currentType === 'files' && (!e.data || e.data.selected.toString() !== currentTargets.toString())) && close();
});
})
.shortcut({
pattern : fm.OS === 'mac' ? 'ctrl+m' : 'contextmenu shift+f10',
description : 'contextmenu',
callback : function(e) {
e.stopPropagation();
e.preventDefault();
$(document).one('contextmenu.' + fm.namespace, function(e) {
e.preventDefault();
e.stopPropagation();
});
var sel = fm.selected(),
type, targets, pos, elm;
if (sel.length) {
type = 'files';
targets = sel;
elm = $('#'+fm.cwdHash2Id(sel[0]));
} else {
type = 'cwd';
targets = [ fm.cwd().hash ];
pos = fm.getUI('workzone').offset();
}
if (! elm || ! elm.length) {
elm = fm.getUI('workzone');
}
pos = elm.offset();
pos.top += (elm.height() / 2);
pos.left += (elm.width() / 2);
fm.trigger('contextmenu', {
'type' : type,
'targets' : targets,
'x' : pos.left,
'y' : pos.top
});
}
});
});
};
/*
* File: /js/ui/cwd.js
*/
/**
* elFinder current working directory ui.
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfindercwd = function(fm, options) {
this.not('.elfinder-cwd').each(function() {
// fm.time('cwdLoad');
var mobile = fm.UA.Mobile,
list = fm.viewType == 'list',
undef = 'undefined',
/**
* Select event full name
*
* @type String
**/
evtSelect = 'select.'+fm.namespace,
/**
* Unselect event full name
*
* @type String
**/
evtUnselect = 'unselect.'+fm.namespace,
/**
* Disable event full name
*
* @type String
**/
evtDisable = 'disable.'+fm.namespace,
/**
* Disable event full name
*
* @type String
**/
evtEnable = 'enable.'+fm.namespace,
c = 'class',
/**
* File css class
*
* @type String
**/
clFile = fm.res(c, 'cwdfile'),
/**
* Selected css class
*
* @type String
**/
fileSelector = '.'+clFile,
/**
* Selected css class
*
* @type String
**/
clSelected = 'ui-selected',
/**
* Disabled css class
*
* @type String
**/
clDisabled = fm.res(c, 'disabled'),
/**
* Draggable css class
*
* @type String
**/
clDraggable = fm.res(c, 'draggable'),
/**
* Droppable css class
*
* @type String
**/
clDroppable = fm.res(c, 'droppable'),
/**
* Hover css class
*
* @type String
**/
clHover = fm.res(c, 'hover'),
/**
* Active css class
*
* @type String
**/
clActive = fm.res(c, 'active'),
/**
* Hover css class
*
* @type String
**/
clDropActive = fm.res(c, 'adroppable'),
/**
* Css class for temporary nodes (for mkdir/mkfile) commands
*
* @type String
**/
clTmp = clFile+'-tmp',
/**
* Select checkbox css class
*
* @type String
*/
clSelChk = 'elfinder-cwd-selectchk',
/**
* Number of thumbnails to load in one request (new api only)
*
* @type Number
**/
tmbNum = fm.options.loadTmbs > 0 ? fm.options.loadTmbs : 5,
/**
* Current search query.
*
* @type String
*/
query = '',
/**
* Currect clipboard(cut) hashes as object key
*
* @type Object
*/
clipCuts = {},
/**
* Parents hashes of cwd
*
* @type Array
*/
cwdParents = [],
/**
* cwd current hashes
*
* @type Array
*/
cwdHashes = [],
/**
* incsearch current hashes
*
* @type Array
*/
incHashes = void 0,
/**
* Custom columns name and order
*
* @type Array
*/
customCols = [],
/**
* Current clicked element id of first time for dblclick
*
* @type String
*/
curClickId = '',
/**
* Custom columns builder
*
* @type Function
*/
customColsBuild = function() {
var cols = '';
for (var i = 0; i < customCols.length; i++) {
cols += '<td class="elfinder-col-'+customCols[i]+'">{' + customCols[i] + '}</td>';
}
return cols;
},
/**
* Make template.row from customCols
*
* @type Function
*/
makeTemplateRow = function() {
return '<tr id="{id}" class="'+clFile+' {permsclass} {dirclass}" title="{tooltip}"{css}><td class="elfinder-col-name"><div class="elfinder-cwd-file-wrapper"><span class="elfinder-cwd-icon {mime}"{style}/>{marker}<span class="elfinder-cwd-filename">{name}</span></div>'+selectCheckbox+'</td>'+customColsBuild()+'</tr>';
},
selectCheckbox = ($.map(options.showSelectCheckboxUA, function(t) {return (fm.UA[t] || t.match(/^all$/i))? true : null;}).length)? '<div class="elfinder-cwd-select"><input type="checkbox" class="'+clSelChk+'"></div>' : '',
colResizing = false,
colWidth = null,
/**
* File templates
*
* @type Object
**/
templates = {
icon : '<div id="{id}" class="'+clFile+' {permsclass} {dirclass} ui-corner-all" title="{tooltip}"><div class="elfinder-cwd-file-wrapper ui-corner-all"><div class="elfinder-cwd-icon {mime} ui-corner-all" unselectable="on"{style}/>{marker}</div><div class="elfinder-cwd-filename" title="{nametitle}">{name}</div>'+selectCheckbox+'</div>',
row : ''
},
permsTpl = fm.res('tpl', 'perms'),
lockTpl = fm.res('tpl', 'lock'),
symlinkTpl = fm.res('tpl', 'symlink'),
/**
* Template placeholders replacement rules
*
* @type Object
**/
replacement = {
id : function(f) {
return fm.cwdHash2Id(f.hash);
},
name : function(f) {
var name = fm.escape(f.i18 || f.name);
!list && (name = name.replace(/([_.])/g, '&#8203;$1'));
return name;
},
nametitle : function(f) {
return fm.escape(f.i18 || f.name);
},
permsclass : function(f) {
return fm.perms2class(f);
},
perm : function(f) {
return fm.formatPermissions(f);
},
dirclass : function(f) {
var cName = f.mime == 'directory' ? 'directory' : '';
f.isroot && (cName += ' isroot');
f.csscls && (cName += ' ' + fm.escape(f.csscls));
options.getClass && (cName += ' ' + options.getClass(f));
return cName;
},
style : function(f) {
return f.icon? fm.getIconStyle(f) : '';
},
mime : function(f) {
var cName = fm.mime2class(f.mime);
f.icon && (cName += ' elfinder-cwd-bgurl');
return cName;
},
size : function(f) {
return (f.mime === 'directory' && !f.size)? '-' : fm.formatSize(f.size);
},
date : function(f) {
return fm.formatDate(f);
},
kind : function(f) {
return fm.mime2kind(f);
},
mode : function(f) {
return f.perm? fm.formatFileMode(f.perm) : '';
},
modestr : function(f) {
return f.perm? fm.formatFileMode(f.perm, 'string') : '';
},
modeoct : function(f) {
return f.perm? fm.formatFileMode(f.perm, 'octal') : '';
},
modeboth : function(f) {
return f.perm? fm.formatFileMode(f.perm, 'both') : '';
},
marker : function(f) {
return (f.alias || f.mime == 'symlink-broken' ? symlinkTpl : '')+(!f.read || !f.write ? permsTpl : '')+(f.locked ? lockTpl : '');
},
tooltip : function(f) {
var title = fm.formatDate(f) + (f.size > 0 ? ' ('+fm.formatSize(f.size)+')' : ''),
info = '';
if (query && f.path) {
info = fm.escape(f.path.replace(/\/[^\/]*$/, ''));
} else {
info = f.tooltip? fm.escape(f.tooltip).replace(/\r/g, '&#13;') : '';
}
if (list) {
info += (info? '&#13;' : '') + fm.escape(f.i18 || f.name);
}
return info? info + '&#13;' + title : title;
}
},
/**
* Type badge CSS added flag
*
* @type Object
*/
addedBadges = {},
/**
* Type badge style sheet element
*
* @type Object
*/
addBadgeStyleSheet,
/**
* Add type badge CSS into 'head'
*
* @type Fundtion
*/
addBadgeStyle = function(mime, name) {
var sel, ext, type;
if (mime && ! addedBadges[mime]) {
if (typeof addBadgeStyleSheet === 'undefined') {
if ($('#elfinderAddBadgeStyle'+fm.namespace).length) {
$('#elfinderAddBadgeStyle'+fm.namespace).remove();
}
addBadgeStyleSheet = $('<style id="addBadgeStyle'+fm.namespace+'"/>').insertBefore($('head').children(':first')).get(0).sheet || null;
}
if (addBadgeStyleSheet) {
mime = mime.toLowerCase();
type = mime.split('/');
ext = fm.escape(fm.mimeTypes[mime] || (name.replace(/.bac?k$/i, '').match(/\.([^.]+)$/) || ['',''])[1]);
if (ext) {
sel = '.elfinder-cwd-icon-' + type[0].replace(/(\.|\+)/g, '-');
if (typeof type[1] !== 'undefined') {
sel += '.elfinder-cwd-icon-' + type[1].replace(/(\.|\+)/g, '-');
}
try {
addBadgeStyleSheet.insertRule(sel + ':before{content:"' + ext.toLowerCase() + '"}', 0);
} catch(e) {}
}
addedBadges[mime] = true;
}
}
},
/**
* Return file html
*
* @param Object file info
* @return String
**/
itemhtml = function(f) {
f.mime && f.mime !== 'directory' && !addedBadges[f.mime] && addBadgeStyle(f.mime, f.name);
return templates[list ? 'row' : 'icon']
.replace(/\{([a-z0-9_]+)\}/g, function(s, e) {
return replacement[e] ? replacement[e](f, fm) : (f[e] ? f[e] : '');
});
},
/**
* jQueery node that will be selected next
*
* @type Object jQuery node
*/
selectedNext = $(),
/**
* Flag. Required for msie to avoid unselect files on dragstart
*
* @type Boolean
**/
selectLock = false,
/**
* Move selection to prev/next file
*
* @param String move direction
* @param Boolean append to current selection
* @return void
* @rise select
*/
select = function(keyCode, append) {
var code = $.ui.keyCode,
prev = keyCode == code.LEFT || keyCode == code.UP,
sel = cwd.find('[id].'+clSelected),
selector = prev ? 'first:' : 'last',
s, n, sib, top, left;
function sibling(n, direction) {
return n[direction+'All']('[id]:not(.'+clDisabled+'):not(.elfinder-cwd-parent):first');
}
if (sel.length) {
s = sel.filter(prev ? ':first' : ':last');
sib = sibling(s, prev ? 'prev' : 'next');
if (!sib.length) {
// there is no sibling on required side - do not move selection
n = s;
} else if (list || keyCode == code.LEFT || keyCode == code.RIGHT) {
// find real prevoius file
n = sib;
} else {
// find up/down side file in icons view
top = s.position().top;
left = s.position().left;
n = s;
if (prev) {
do {
n = n.prev('[id]');
} while (n.length && !(n.position().top < top && n.position().left <= left));
if (n.hasClass(clDisabled)) {
n = sibling(n, 'next');
}
} else {
do {
n = n.next('[id]');
} while (n.length && !(n.position().top > top && n.position().left >= left));
if (n.hasClass(clDisabled)) {
n = sibling(n, 'prev');
}
// there is row before last one - select last file
if (!n.length) {
sib = cwd.find('[id]:not(.'+clDisabled+'):last');
if (sib.position().top > top) {
n = sib;
}
}
}
}
// !append && unselectAll();
} else {
if (selectedNext.length) {
n = prev? selectedNext.prev() : selectedNext;
} else {
// there are no selected file - select first/last one
n = cwd.find('[id]:not(.'+clDisabled+'):not(.elfinder-cwd-parent):'+(prev ? 'last' : 'first'));
}
}
if (n && n.length && !n.hasClass('elfinder-cwd-parent')) {
if (s && append) {
// append new files to selected
n = s.add(s[prev ? 'prevUntil' : 'nextUntil']('#'+n.attr('id'))).add(n);
} else {
// unselect selected files
sel.trigger(evtUnselect);
}
// select file(s)
n.trigger(evtSelect);
// set its visible
scrollToView(n.filter(prev ? ':first' : ':last'));
// update cache/view
trigger();
}
},
selectedFiles = {},
selectFile = function(hash) {
$('#'+fm.cwdHash2Id(hash)).trigger(evtSelect);
},
allSelected = false,
selectAll = function() {
var phash = fm.cwd().hash;
selectCheckbox && selectAllCheckbox.find('input').prop('checked', true);
fm.lazy(function() {
var files;
if (fm.maxTargets && (incHashes || cwdHashes).length > fm.maxTargets) {
unselectAll({ notrigger: true });
files = $.map(incHashes || cwdHashes, function(hash) { return fm.file(hash) || null; });
files = files.slice(0, fm.maxTargets);
selectedFiles = {};
$.each(files, function(i, v) {
selectedFiles[v.hash] = true;
$('#'+fm.cwdHash2Id(v.hash)).trigger(evtSelect);
});
fm.toast({mode: 'warning', msg: fm.i18n(['errMaxTargets', fm.maxTargets])});
} else {
cwd.find('[id]:not(.'+clSelected+'):not(.elfinder-cwd-parent)').trigger(evtSelect);
selectedFiles = fm.arrayFlip(incHashes || cwdHashes, true);
}
trigger();
selectCheckbox && selectAllCheckbox.data('pending', false);
}, 0, {repaint: true});
},
/**
* Unselect all files
*
* @param Object options
* @return void
*/
unselectAll = function(opts) {
var o = opts || {};
selectCheckbox && selectAllCheckbox.find('input').prop('checked', false);
if (Object.keys(selectedFiles).length) {
selectLock = false;
selectedFiles = {};
cwd.find('[id].'+clSelected).trigger(evtUnselect);
selectCheckbox && cwd.find('input:checkbox.'+clSelChk).prop('checked', false);
}
!o.notrigger && trigger();
selectCheckbox && selectAllCheckbox.data('pending', false);
cwd.removeClass('elfinder-cwd-allselected');
},
selectInvert = function() {
var invHashes = {};
if (allSelected) {
unselectAll();
} else if (! Object.keys(selectedFiles).length) {
selectAll();
} else {
$.each((incHashes || cwdHashes), function(i, h) {
var itemNode = $('#'+fm.cwdHash2Id(h));
if (! selectedFiles[h]) {
invHashes[h] = true;
itemNode.length && itemNode.trigger(evtSelect);
} else {
itemNode.length && itemNode.trigger(evtUnselect);
}
});
selectedFiles = invHashes;
trigger();
}
},
/**
* Return selected files hashes list
*
* @return Array
*/
selected = function() {
return Object.keys(selectedFiles);
},
/**
* Last selected node id
*
* @type String|Void
*/
lastSelect = void 0,
/**
* Fire elfinder "select" event and pass selected files to it
*
* @return void
*/
trigger = function() {
var selected = Object.keys(selectedFiles),
opts = {
selected : selected,
origin : 'cwd'
};
if (oldSchoolItem && (selected.length > 1 || selected[0] !== fm.cwdId2Hash(
oldSchoolItem.attr('id'))) && oldSchoolItem.hasClass(clSelected)) {
oldSchoolItem.trigger(evtUnselect);
}
allSelected = selected.length && (selected.length === (incHashes || cwdHashes).length) && (!fm.maxTargets || selected.length <= fm.maxTargets);
if (selectCheckbox) {
selectAllCheckbox.find('input').prop('checked', allSelected);
cwd[allSelected? 'addClass' : 'removeClass']('elfinder-cwd-allselected');
}
if (allSelected) {
opts.selectall = true;
} else if (! selected.length) {
opts.unselectall = true;
}
fm.trigger('select', opts);
},
/**
* Scroll file to set it visible
*
* @param DOMElement file/dir node
* @return void
*/
scrollToView = function(o, blink) {
if (! o.length) {
return;
}
var ftop = o.position().top,
fheight = o.outerHeight(true),
wtop = wrapper.scrollTop(),
wheight = wrapper.get(0).clientHeight,
thheight = tableHeader? tableHeader.outerHeight(true) : 0;
if (ftop + thheight + fheight > wtop + wheight) {
wrapper.scrollTop(parseInt(ftop + thheight + fheight - wheight));
} else if (ftop < wtop) {
wrapper.scrollTop(ftop);
}
list && wrapper.scrollLeft(0);
!!blink && fm.resources.blink(o, 'lookme');
},
/**
* Files we get from server but not show yet
*
* @type Array
**/
buffer = [],
/**
* Extra data of buffer
*
* @type Object
**/
bufferExt = {},
/**
* Return index of elements with required hash in buffer
*
* @param String file hash
* @return Number
*/
index = function(hash) {
var l = buffer.length;
while (l--) {
if (buffer[l].hash == hash) {
return l;
}
}
return -1;
},
/**
* Scroll start event name
*
* @type String
**/
scrollStartEvent = 'elfscrstart',
/**
* Scroll stop event name
*
* @type String
**/
scrollEvent = 'elfscrstop',
scrolling = false,
/**
* jQuery UI selectable option
*
* @type Object
*/
selectableOption = {
disabled : true,
filter : '[id]:first',
stop : trigger,
delay : 250,
appendTo : 'body',
autoRefresh: false,
selected : function(e, ui) { $(ui.selected).trigger(evtSelect); },
unselected : function(e, ui) { $(ui.unselected).trigger(evtUnselect); }
},
/**
* hashes of items displayed in current view
*
* @type Object ItemHash => DomId
*/
inViewHashes = {},
/**
* Processing when the current view is changed (On open, search, scroll, resize etc.)
*
* @return void
*/
wrapperRepaint = function(init, recnt) {
var firstNode = (list? cwd.find('tbody:first') : cwd).children('[id]:first');
if (!firstNode.length) {
return;
}
var selectable = cwd.data('selectable'),
rec = (function() {
var wos = wrapper.offset(),
w = $(window),
x = (firstNode.width() / 2) * (!list && options.oldSchool? 3 : 1),
l = wos.left - w.scrollLeft() + (fm.direction === 'ltr'? x : wrapper.width() - x),
t = wos.top - w.scrollTop() + 10 + (list? (bufferExt.itemH * (options.oldSchool? 2 : 1)) || (fm.UA.Touch? 36 : 24) : 0);
return {left: Math.max(0, Math.round(l)), top: Math.max(0, Math.round(t))};
})(),
tgt = init? firstNode : $(document.elementFromPoint(rec.left , rec.top)),
ids = {},
tmbs = {},
multi = 5,
cnt = Math.ceil((bufferExt.hpi? Math.ceil((wz.data('rectangle').height / bufferExt.hpi) * 1.5) : showFiles) / multi),
chk = function() {
var id, hash, file, i;
for (i = 0; i < multi; i++) {
id = tgt.attr('id');
if (id) {
bufferExt.getTmbs = [];
hash = fm.cwdId2Hash(id);
inViewHashes[hash] = id;
// for tmbs
if (bufferExt.attachTmbs[hash]) {
tmbs[hash] = bufferExt.attachTmbs[hash];
}
// for selectable
selectable && (ids[id] = true);
}
// next node
tgt = tgt.next();
if (!tgt.length) {
break;
}
}
},
done = function() {
var idsArr;
if (cwd.data('selectable')) {
Object.assign(ids, selectedFiles);
idsArr = Object.keys(ids);
if (idsArr.length) {
selectableOption.filter = '#'+idsArr.join(', #');
cwd.selectable('enable').selectable('option', {filter : selectableOption.filter}).selectable('refresh');
}
}
if (Object.keys(tmbs).length) {
bufferExt.getTmbs = [];
attachThumbnails(tmbs);
}
},
setTarget = function() {
if (!tgt.hasClass(clFile)) {
tgt = tgt.closest(fileSelector);
}
},
arr, widget;
inViewHashes = {};
selectable && cwd.selectable('option', 'disabled');
if (tgt.length) {
if (!tgt.hasClass(clFile) && !tgt.closest(fileSelector).length) {
// dialog, serach button etc.
widget = fm.getUI().find('.ui-dialog:visible,.ui-widget:visible');
if (widget.length) {
widget.hide();
tgt = $(document.elementFromPoint(rec.left , rec.top));
widget.show();
} else {
widget = null;
}
}
setTarget();
if (!tgt.length) {
// try search 5px down
widget && widget.hide();
tgt = $(document.elementFromPoint(rec.left , rec.top + 5));
widget && widget.show();
setTarget();
}
}
if (tgt.length) {
if (tgt.attr('id')) {
if (init) {
for (var i = 0; i < cnt; i++) {
chk();
if (! tgt.length) {
break;
}
}
done();
} else {
bufferExt.repaintJob && bufferExt.repaintJob.state() === 'pending' && bufferExt.repaintJob.reject();
arr = new Array(cnt);
bufferExt.repaintJob = fm.asyncJob(function() {
chk();
if (! tgt.length) {
done();
bufferExt.repaintJob && bufferExt.repaintJob.state() === 'pending' && bufferExt.repaintJob.reject();
}
}, arr).done(done);
}
}
} else if (init && bufferExt.renderd) {
// In initial request, cwd DOM not renderd so doing lazy check
recnt = recnt || 0;
if (recnt < 10) { // Prevent infinite loop
requestAnimationFrame(function() {
wrapperRepaint(init, ++recnt);
});
}
}
},
/**
* Item node of oldScholl ".."
*/
oldSchoolItem = null,
/**
* display parent folder with ".." name
*
* @param String phash
* @return void
*/
oldSchool = function(p) {
var phash = fm.cwd().phash,
pdir = fm.file(phash) || null,
set = function(pdir) {
if (pdir) {
oldSchoolItem = $(itemhtml($.extend(true, {}, pdir, {name : '..', i18 : '..', mime : 'directory'})))
.addClass('elfinder-cwd-parent')
.on('dblclick', function() {
var hash = fm.cwdId2Hash(this.id);
fm.trigger('select', {selected : [hash]}).exec('open', hash);
});
(list ? oldSchoolItem.children('td:first') : oldSchoolItem).children('.elfinder-cwd-select').remove();
(list ? cwd.find('tbody') : cwd).prepend(oldSchoolItem);
}
};
if (pdir) {
set(pdir);
} else {
if (fm.getUI('tree').length) {
fm.one('parents', function() {
set(fm.file(phash) || null);
wrapper.trigger(scrollEvent);
});
} else {
fm.request({
data : {cmd : 'parents', target : fm.cwd().hash},
preventFail : true
})
.done(function(data) {
set(fm.file(phash) || null);
wrapper.trigger(scrollEvent);
});
}
}
},
showFiles = fm.options.showFiles,
/**
* Cwd scroll event handler.
* Lazy load - append to cwd not shown files
*
* @return void
*/
render = function() {
if (bufferExt.rendering || (bufferExt.renderd && ! buffer.length)) {
return;
}
var place = (list ? cwd.children('table').children('tbody') : cwd),
phash,
chk,
// created document fragment for jQuery >= 1.12, 2.2, 3.0
// see Studio-42/elFinder#1544 @ github
docFlag = $.htmlPrefilter? true : false,
tempDom = docFlag? $(document.createDocumentFragment()) : $('<div/>'),
go = function(o){
var over = o || null,
html = [],
dirs = false,
atmb = {},
stmb = (fm.option('tmbUrl') === 'self'),
init = bufferExt.renderd? false : true,
files, locks, selected;
files = buffer.splice(0, showFiles + (over || 0) / (bufferExt.hpi || 1));
bufferExt.renderd += files.length;
if (! buffer.length) {
bottomMarker.hide();
wrapper.off(scrollEvent, render);
}
locks = [];
html = $.map(files, function(f) {
if (f.hash && f.name) {
if (f.mime == 'directory') {
dirs = true;
}
if ((f.tmb && (f.tmb != 1 || f.size > 0)) || (stmb && f.mime.indexOf('image/') === 0)) {
atmb[f.hash] = f.tmb || 'self';
}
clipCuts[f.hash] && locks.push(f.hash);
return itemhtml(f);
}
return null;
});
// html into temp node
tempDom.empty().append(html.join(''));
// make directory droppable
dirs && !mobile && makeDroppable(tempDom);
// check selected items
selected = [];
if (Object.keys(selectedFiles).length) {
tempDom.find('[id]:not(.'+clSelected+'):not(.elfinder-cwd-parent)').each(function() {
selectedFiles[fm.cwdId2Hash(this.id)] && selected.push($(this));
});
}
// append to cwd
place.append(docFlag? tempDom : tempDom.children());
// trigger select
if (selected.length) {
$.each(selected, function(i, n) { n.trigger(evtSelect); });
trigger();
}
locks.length && fm.trigger('lockfiles', {files: locks});
!bufferExt.hpi && bottomMarkerShow(place, files.length);
if (list) {
// show thead
cwd.find('thead').show();
// fixed table header
fixTableHeader({fitWidth: ! colWidth});
}
if (Object.keys(atmb).length) {
Object.assign(bufferExt.attachTmbs, atmb);
}
if (init) {
if (! mobile && ! cwd.data('selectable')) {
// make files selectable
cwd.selectable(selectableOption).data('selectable', true);
}
wrapperRepaint(true);
}
! scrolling && wrapper.trigger(scrollEvent);
};
if (! bufferExt.renderd) {
// first time to go()
bufferExt.rendering = true;
// scroll top on dir load to avoid scroll after page reload
wrapper.scrollTop(0);
phash = fm.cwd().phash;
go();
if (options.oldSchool) {
if (phash && !query) {
oldSchool(phash);
} else {
oldSchoolItem = $();
}
}
if (list) {
colWidth && setColwidth();
fixTableHeader({fitWidth: true});
}
bufferExt.itemH = (list? place.find('tr:first') : place.find('[id]:first')).outerHeight(true);
fm.trigger('cwdrender');
bufferExt.rendering = false;
}
if (! bufferExt.rendering && buffer.length) {
// next go()
if ((chk = (wrapper.height() + wrapper.scrollTop() + fm.options.showThreshold + bufferExt.row) - (bufferExt.renderd * bufferExt.hpi)) > 0) {
bufferExt.rendering = true;
fm.lazy(function() {
go(chk);
bufferExt.rendering = false;
});
} else {
!fm.enabled() && resize();
}
} else {
resize();
}
},
// fixed table header jQuery object
tableHeader = null,
// Is UA support CSS sticky
cssSticky = fm.UA.CSS.positionSticky && fm.UA.CSS.widthMaxContent,
// To fixed table header colmun
fixTableHeader = function(optsArg) {
if (! options.listView.fixedHeader) {
return;
}
var setPos = function() {
var val, pos;
pos = (fm.direction === 'ltr')? 'left' : 'right';
val = ((fm.direction === 'ltr')? wrapper.scrollLeft() : table.outerWidth(true) - wrapper.width() - wrapper.scrollLeft()) * -1;
if (base.css(pos) !== val) {
base.css(pos, val);
}
},
opts = optsArg || {},
cnt, base, table, htable, thead, tbody, hheight, htr, btr, htd, btd, htw, btw, init;
tbody = cwd.find('tbody');
btr = tbody.children('tr:first');
if (btr.length && btr.is(':visible')) {
table = tbody.parent();
if (! tableHeader) {
init = true;
tbody.addClass('elfinder-cwd-fixheader');
thead = cwd.find('thead').attr('id', fm.namespace+'-cwd-thead');
htr = thead.children('tr:first');
hheight = htr.outerHeight(true);
cwd.css('margin-top', hheight - parseInt(table.css('padding-top')));
if (cssSticky) {
tableHeader = $('<div class="elfinder-table-header-sticky"/>').addClass(cwd.attr('class')).append($('<table/>').append(thead));
cwd.after(tableHeader);
wrapper.on('resize.fixheader', function(e) {
e.stopPropagation();
fixTableHeader({fitWidth: true});
});
} else {
base = $('<div/>').addClass(cwd.attr('class')).append($('<table/>').append(thead));
tableHeader = $('<div/>').addClass(wrapper.attr('class') + ' elfinder-cwd-fixheader')
.removeClass('ui-droppable native-droppable')
.css(wrapper.position())
.css({ height: hheight, width: cwd.outerWidth() })
.append(base);
if (fm.direction === 'rtl') {
tableHeader.css('left', (wrapper.data('width') - wrapper.width()) + 'px');
}
setPos();
wrapper.after(tableHeader)
.on('scroll.fixheader resize.fixheader', function(e) {
setPos();
if (e.type === 'resize') {
e.stopPropagation();
tableHeader.css(wrapper.position());
wrapper.data('width', wrapper.css('overflow', 'hidden').width());
wrapper.css('overflow', 'auto');
fixTableHeader();
}
});
}
} else {
thead = $('#'+fm.namespace+'-cwd-thead');
htr = thead.children('tr:first');
}
if (init || opts.fitWidth || Math.abs(btr.outerWidth() - htr.outerWidth()) > 2) {
cnt = customCols.length + 1;
for (var i = 0; i < cnt; i++) {
htd = htr.children('td:eq('+i+')');
btd = btr.children('td:eq('+i+')');
htw = htd.width();
btw = btd.width();
if (typeof htd.data('delta') === 'undefined') {
htd.data('delta', (htd.outerWidth() - htw) - (btd.outerWidth() - btw));
}
btw -= htd.data('delta');
if (! init && ! opts.fitWidth && htw === btw) {
break;
}
htd.css('width', btw + 'px');
}
}
if (!cssSticky) {
tableHeader.data('widthTimer') && cancelAnimationFrame(tableHeader.data('widthTimer'));
tableHeader.data('widthTimer', requestAnimationFrame(function() {
if (tableHeader) {
tableHeader.css('width', mBoard.width() + 'px');
if (fm.direction === 'rtl') {
tableHeader.css('left', (wrapper.data('width') - wrapper.width()) + 'px');
}
}
}));
}
}
},
// Set colmun width
setColwidth = function() {
if (list && colWidth) {
var cl = 'elfinder-cwd-colwidth',
first = cwd.find('tr[id]:first'),
former;
if (! first.hasClass(cl)) {
former = cwd.find('tr.'+cl);
former.removeClass(cl).find('td').css('width', '');
first.addClass(cl);
cwd.find('table:first').css('table-layout', 'fixed');
$.each($.merge(['name'], customCols), function(i, k) {
var w = colWidth[k] || first.find('td.elfinder-col-'+k).width();
first.find('td.elfinder-col-'+k).width(w);
});
}
}
},
/**
* Droppable options for cwd.
* Drop target is `wrapper`
* Do not add class on childs file over
*
* @type Object
*/
droppable = Object.assign({}, fm.droppable, {
over : function(e, ui) {
var dst = $(this),
helper = ui.helper,
ctr = (e.shiftKey || e.ctrlKey || e.metaKey),
hash, status, inParent;
e.stopPropagation();
helper.data('dropover', helper.data('dropover') + 1);
dst.data('dropover', true);
if (helper.data('namespace') !== fm.namespace || ! fm.insideWorkzone(e.pageX, e.pageY)) {
dst.removeClass(clDropActive);
helper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus');
return;
}
if (dst.hasClass(fm.res(c, 'cwdfile'))) {
hash = fm.cwdId2Hash(dst.attr('id'));
dst.data('dropover', hash);
} else {
hash = fm.cwd().hash;
fm.cwd().write && dst.data('dropover', hash);
}
inParent = (fm.file(helper.data('files')[0]).phash === hash);
if (dst.data('dropover') === hash) {
$.each(helper.data('files'), function(i, h) {
if (h === hash || (inParent && !ctr && !helper.hasClass('elfinder-drag-helper-plus'))) {
dst.removeClass(clDropActive);
return false; // break $.each
}
});
} else {
dst.removeClass(clDropActive);
}
if (helper.data('locked') || inParent) {
status = 'elfinder-drag-helper-plus';
} else {
status = 'elfinder-drag-helper-move';
if (ctr) {
status += ' elfinder-drag-helper-plus';
}
}
dst.hasClass(clDropActive) && helper.addClass(status);
requestAnimationFrame(function(){ dst.hasClass(clDropActive) && helper.addClass(status); });
},
out : function(e, ui) {
var helper = ui.helper;
e.stopPropagation();
helper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus').data('dropover', Math.max(helper.data('dropover') - 1, 0));
$(this).removeData('dropover')
.removeClass(clDropActive);
},
deactivate : function() {
$(this).removeData('dropover')
.removeClass(clDropActive);
},
drop : function(e, ui) {
unselectAll({ notrigger: true });
fm.droppable.drop.call(this, e, ui);
}
}),
/**
* Make directory droppable
*
* @return void
*/
makeDroppable = function(place) {
place = place? place : (list ? cwd.find('tbody') : cwd);
var targets = place.children('.directory:not(.'+clDroppable+',.elfinder-na,.elfinder-ro)');
if (fm.isCommandEnabled('paste')) {
targets.droppable(droppable);
}
if (fm.isCommandEnabled('upload')) {
targets.addClass('native-droppable');
}
place.children('.isroot').each(function(i, n) {
var $n = $(n),
hash = fm.cwdId2Hash(n.id);
if (fm.isCommandEnabled('paste', hash)) {
if (! $n.hasClass(clDroppable+',elfinder-na,elfinder-ro')) {
$n.droppable(droppable);
}
} else {
if ($n.hasClass(clDroppable)) {
$n.droppable('destroy');
}
}
if (fm.isCommandEnabled('upload', hash)) {
if (! $n.hasClass('native-droppable,elfinder-na,elfinder-ro')) {
$n.addClass('native-droppable');
}
} else {
if ($n.hasClass('native-droppable')) {
$n.removeClass('native-droppable');
}
}
});
},
/**
* Preload required thumbnails and on load add css to files.
* Return false if required file is not visible yet (in buffer) -
* required for old api to stop loading thumbnails.
*
* @param Object file hash -> thumbnail map
* @param Bool reload
* @return void
*/
attachThumbnails = function(tmbs, reload) {
var attach = function(node, tmb) {
$('<img/>')
.on('load', function() {
node.find('.elfinder-cwd-icon').addClass(tmb.className).css('background-image', "url('"+tmb.url+"')");
})
.attr('src', tmb.url);
},
chk = function(hash, tmb) {
var node = $('#'+fm.cwdHash2Id(hash)),
file, tmbObj, reloads = [];
if (node.length) {
if (tmb != '1') {
file = fm.file(hash);
if (file.tmb !== tmb) {
file.tmb = tmb;
}
tmbObj = fm.tmb(file);
if (reload) {
node.find('.elfinder-cwd-icon').addClass(tmbObj.className).css('background-image', "url('"+tmbObj.url+"')");
} else {
attach(node, tmbObj);
}
delete bufferExt.attachTmbs[hash];
} else {
if (reload) {
loadThumbnails([hash]);
} else if (! bufferExt.tmbLoading[hash]) {
bufferExt.getTmbs.push(hash);
}
}
}
};
if ($.isPlainObject(tmbs) && Object.keys(tmbs).length) {
Object.assign(bufferExt.attachTmbs, tmbs);
$.each(tmbs, chk);
if (! reload && bufferExt.getTmbs.length && ! Object.keys(bufferExt.tmbLoading).length) {
loadThumbnails();
}
}
},
/**
* Load thumbnails from backend.
*
* @param Array|void reloads hashes list for reload thumbnail items
* @return void
*/
loadThumbnails = function(reloads) {
var tmbs = [],
reload = false;
if (fm.oldAPI) {
fm.request({
data : {cmd : 'tmb', current : fm.cwd().hash},
preventFail : true
})
.done(function(data) {
if (data.images && Object.keys(data.images).length) {
attachThumbnails(data.images);
}
if (data.tmb) {
loadThumbnails();
}
});
return;
}
if (reloads) {
reload = true;
tmbs = reloads.splice(0, tmbNum);
} else {
tmbs = bufferExt.getTmbs.splice(0, tmbNum);
}
if (tmbs.length) {
if (reload || inViewHashes[tmbs[0]] || inViewHashes[tmbs[tmbs.length-1]]) {
$.each(tmbs, function(i, h) {
bufferExt.tmbLoading[h] = true;
});
fm.request({
data : {cmd : 'tmb', targets : tmbs},
preventFail : true
})
.done(function(data) {
var errs = [],
resLen;
if (data.images) {
if (resLen = Object.keys(data.images).length) {
if (resLen < tmbs.length) {
$.each(tmbs, function(i, h) {
if (! data.images[h]) {
errs.push(h);
}
});
}
attachThumbnails(data.images, reload);
} else {
errs = tmbs;
}
// unset error items from bufferExt.attachTmbs
if (errs.length) {
$.each(errs, function(i, h) {
delete bufferExt.attachTmbs[h];
});
}
}
if (reload) {
if (reloads.length) {
loadThumbnails(reloads);
}
}
})
.always(function() {
bufferExt.tmbLoading = {};
if (! reload && bufferExt.getTmbs.length) {
loadThumbnails();
}
});
}
}
},
/**
* Add new files to cwd/buffer
*
* @param Array new files
* @return void
*/
add = function(files, mode) {
var place = list ? cwd.find('tbody') : cwd,
l = files.length,
atmb = {},
findNode = function(file) {
var pointer = cwd.find('[id]:first'), file2;
while (pointer.length) {
file2 = fm.file(fm.cwdId2Hash(pointer.attr('id')));
if (!pointer.hasClass('elfinder-cwd-parent') && file2 && fm.compare(file, file2) < 0) {
return pointer;
}
pointer = pointer.next('[id]');
}
},
findIndex = function(file) {
var l = buffer.length, i;
for (i =0; i < l; i++) {
if (fm.compare(file, buffer[i]) < 0) {
return i;
}
}
return l || -1;
},
// created document fragment for jQuery >= 1.12, 2.2, 3.0
// see Studio-42/elFinder#1544 @ github
docFlag = $.htmlPrefilter? true : false,
tempDom = docFlag? $(document.createDocumentFragment()) : $('<div/>'),
file, hash, node, nodes, ndx, stmb;
if (l > showFiles) {
// re-render for performance tune
content();
selectedFiles = fm.arrayFlip($.map(files, function(f) { return f.hash; }), true);
trigger();
} else {
// add the item immediately
l && wz.removeClass('elfinder-cwd-wrapper-empty');
// Self thumbnail
stmb = (fm.option('tmbUrl') === 'self');
while (l--) {
file = files[l];
hash = file.hash;
if ($('#'+fm.cwdHash2Id(hash)).length) {
continue;
}
if ((node = findNode(file)) && ! node.length) {
node = null;
}
if (! node && (ndx = findIndex(file)) >= 0) {
buffer.splice(ndx, 0, file);
} else {
tempDom.empty().append(itemhtml(file));
(file.mime === 'directory') && !mobile && makeDroppable(tempDom);
nodes = docFlag? tempDom : tempDom.children();
if (node) {
node.before(nodes);
} else {
place.append(nodes);
}
}
if ($('#'+fm.cwdHash2Id(hash)).length) {
if ((file.tmb && (file.tmb != 1 || file.size > 0)) || (stmb && file.mime.indexOf('image/') === 0)) {
atmb[hash] = file.tmb || 'self';
}
}
}
if (list) {
setColwidth();
fixTableHeader({fitWidth: ! colWidth});
}
bottomMarkerShow(place);
if (Object.keys(atmb).length) {
Object.assign(bufferExt.attachTmbs, atmb);
}
}
},
/**
* Remove files from cwd/buffer
*
* @param Array files hashes
* @return void
*/
remove = function(files) {
var l = files.length,
inSearch = fm.searchStatus.state > 1,
curCmd = fm.getCommand(fm.currentReqCmd) || {},
hash, n, ndx, found;
// removed cwd
if (!fm.cwd().hash && !curCmd.noChangeDirOnRemovedCwd) {
$.each(cwdParents.reverse(), function(i, h) {
if (fm.file(h)) {
found = true;
fm.one(fm.currentReqCmd + 'done', function() {
!fm.cwd().hash && fm.exec('open', h);
});
return false;
}
});
// fallback to fm.roots[0]
!found && !fm.cwd().hash && fm.exec('open', fm.roots[Object.keys(fm.roots)[0]]);
return;
}
while (l--) {
hash = files[l];
if ((n = $('#'+fm.cwdHash2Id(hash))).length) {
try {
n.remove();
--bufferExt.renderd;
} catch(e) {
fm.debug('error', e);
}
} else if ((ndx = index(hash)) !== -1) {
buffer.splice(ndx, 1);
}
selectedFiles[hash] && delete selectedFiles[hash];
if (inSearch) {
if ((ndx = $.inArray(hash, cwdHashes)) !== -1) {
cwdHashes.splice(ndx, 1);
}
}
}
inSearch && fm.trigger('cwdhasheschange', cwdHashes);
if (list) {
setColwidth();
fixTableHeader({fitWidth: ! colWidth});
}
},
customColsNameBuild = function() {
var name = '',
customColsName = '';
for (var i = 0; i < customCols.length; i++) {
name = fm.getColumnName(customCols[i]);
customColsName +='<td class="elfinder-cwd-view-th-'+customCols[i]+' sortable-item">'+name+'</td>';
}
return customColsName;
},
setItemBoxSize = function(boxSize) {
var place, elm;
if (!boxSize.height) {
place = (list ? cwd.find('tbody') : cwd);
elm = place.find(list? 'tr:first' : '[id]:first');
boxSize.height = elm.outerHeight(true);
if (!list) {
boxSize.width = elm.outerWidth(true);
}
}
},
bottomMarkerShow = function(cur, cnt) {
var place = cur || (list ? cwd.find('tbody') : cwd),
boxSize = itemBoxSize[fm.viewType],
col = 1,
row;
if (buffer.length > 0) {
if (!bufferExt.hpi) {
setItemBoxSize(boxSize);
if (! list) {
col = Math.floor(place.width() / boxSize.width);
bufferExt.row = boxSize.height;
bufferExt.hpi = bufferExt.row / col;
} else {
bufferExt.row = bufferExt.hpi = boxSize.height;
}
} else if (!list) {
col = Math.floor(place.width() / boxSize.width);
}
row = Math.ceil((buffer.length + (cnt || 0)) / col);
if (list && tableHeader) {
++row;
}
bottomMarker.css({top: (bufferExt.row * row) + 'px'}).show();
}
},
wrapperContextMenu = {
contextmenu : function(e) {
e.preventDefault();
if (cwd.data('longtap') !== void(0)) {
e.stopPropagation();
return;
}
fm.trigger('contextmenu', {
'type' : 'cwd',
'targets' : [fm.cwd().hash],
'x' : e.pageX,
'y' : e.pageY
});
},
touchstart : function(e) {
if (e.originalEvent.touches.length > 1) {
return;
}
if (cwd.data('longtap') !== false) {
wrapper.data('touching', {x: e.originalEvent.touches[0].pageX, y: e.originalEvent.touches[0].pageY});
cwd.data('tmlongtap', setTimeout(function(){
// long tap
cwd.data('longtap', true);
fm.trigger('contextmenu', {
'type' : 'cwd',
'targets' : [fm.cwd().hash],
'x' : wrapper.data('touching').x,
'y' : wrapper.data('touching').y
});
}, 500));
}
cwd.data('longtap', null);
},
touchend : function(e) {
if (e.type === 'touchmove') {
if (! wrapper.data('touching') ||
( Math.abs(wrapper.data('touching').x - e.originalEvent.touches[0].pageX)
+ Math.abs(wrapper.data('touching').y - e.originalEvent.touches[0].pageY)) > 4) {
wrapper.data('touching', null);
}
} else {
setTimeout(function() {
cwd.removeData('longtap');
}, 80);
}
clearTimeout(cwd.data('tmlongtap'));
},
click : function(e) {
if (cwd.data('longtap')) {
e.preventDefault();
e.stopPropagation();
}
}
},
/**
* Update directory content
*
* @return void
*/
content = function() {
fm.lazy(function() {
var phash, emptyMethod, thtr;
wz.append(selectAllCheckbox).removeClass('elfinder-cwd-wrapper-empty elfinder-search-result elfinder-incsearch-result elfinder-letsearch-result');
if (fm.searchStatus.state > 1 || fm.searchStatus.ininc) {
wz.addClass('elfinder-search-result' + (fm.searchStatus.ininc? ' elfinder-'+(query.substr(0,1) === '/' ? 'let':'inc')+'search-result' : ''));
}
// abort attachThumbJob
bufferExt.attachThumbJob && bufferExt.attachThumbJob._abort();
// destroy selectable for GC
cwd.data('selectable') && cwd.selectable('disable').selectable('destroy').removeData('selectable');
// notify cwd init
fm.trigger('cwdinit');
selectedNext = $();
try {
// to avoid problem with draggable
cwd.empty();
} catch (e) {
cwd.html('');
}
if (tableHeader) {
wrapper.off('scroll.fixheader resize.fixheader');
tableHeader.remove();
tableHeader = null;
}
cwd.removeClass('elfinder-cwd-view-icons elfinder-cwd-view-list')
.addClass('elfinder-cwd-view-'+(list ? 'list' :'icons'))
.attr('style', '')
.css('height', 'auto');
bottomMarker.hide();
wrapper[list ? 'addClass' : 'removeClass']('elfinder-cwd-wrapper-list')._padding = parseInt(wrapper.css('padding-top')) + parseInt(wrapper.css('padding-bottom'));
if (fm.UA.iOS) {
wrapper.removeClass('overflow-scrolling-touch').addClass('overflow-scrolling-touch');
}
if (list) {
cwd.html('<table><thead/><tbody/></table>');
thtr = $('<tr class="ui-state-default"><td class="elfinder-cwd-view-th-name">'+fm.getColumnName('name')+'</td>'+customColsNameBuild()+'</tr>');
cwd.find('thead').hide().append(thtr).find('td:first').append(selectAllCheckbox);
if ($.fn.sortable) {
thtr.addClass('touch-punch touch-punch-keep-default')
.sortable({
axis: 'x',
distance: 8,
items: '> .sortable-item',
start: function(e, ui) {
$(ui.item[0]).data('dragging', true);
ui.placeholder
.width(ui.helper.removeClass('ui-state-hover').width())
.removeClass('ui-state-active')
.addClass('ui-state-hover')
.css('visibility', 'visible');
},
update: function(e, ui){
var target = $(ui.item[0]).attr('class').split(' ')[0].replace('elfinder-cwd-view-th-', ''),
prev, done;
customCols = $.map($(this).children(), function(n) {
var name = $(n).attr('class').split(' ')[0].replace('elfinder-cwd-view-th-', '');
if (! done) {
if (target === name) {
done = true;
} else {
prev = name;
}
}
return (name === 'name')? null : name;
});
templates.row = makeTemplateRow();
fm.storage('cwdCols', customCols);
prev = '.elfinder-col-'+prev+':first';
target = '.elfinder-col-'+target+':first';
fm.lazy(function() {
cwd.find('tbody tr').each(function() {
var $this = $(this);
$this.children(prev).after($this.children(target));
});
});
},
stop: function(e, ui) {
setTimeout(function() {
$(ui.item[0]).removeData('dragging');
}, 100);
}
});
}
thtr.find('td').addClass('touch-punch').resizable({
handles: fm.direction === 'ltr'? 'e' : 'w',
start: function(e, ui) {
var target = cwd.find('td.elfinder-col-'
+ ui.element.attr('class').split(' ')[0].replace('elfinder-cwd-view-th-', '')
+ ':first');
ui.element
.data('dragging', true)
.data('resizeTarget', target)
.data('targetWidth', target.width());
colResizing = true;
if (cwd.find('table').css('table-layout') !== 'fixed') {
cwd.find('tbody tr:first td').each(function() {
$(this).width($(this).width());
});
cwd.find('table').css('table-layout', 'fixed');
}
},
resize: function(e, ui) {
ui.element.data('resizeTarget').width(ui.element.data('targetWidth') - (ui.originalSize.width - ui.size.width));
},
stop : function(e, ui) {
colResizing = false;
fixTableHeader({fitWidth: true});
colWidth = {};
cwd.find('tbody tr:first td').each(function() {
var name = $(this).attr('class').split(' ')[0].replace('elfinder-col-', '');
colWidth[name] = $(this).width();
});
fm.storage('cwdColWidth', colWidth);
setTimeout(function() {
ui.element.removeData('dragging');
}, 100);
}
})
.find('.ui-resizable-handle').addClass('ui-icon ui-icon-grip-dotted-vertical');
}
buffer = $.map(incHashes || cwdHashes, function(hash) { return fm.file(hash) || null; });
buffer = fm.sortFiles(buffer);
if (incHashes) {
incHashes = $.map(buffer, function(f) { return f.hash; });
} else {
cwdHashes = $.map(buffer, function(f) { return f.hash; });
}
bufferExt = {
renderd: 0,
attachTmbs: {},
getTmbs: [],
tmbLoading: {},
lazyOpts: { tm : 0 }
};
wz[(buffer.length < 1) ? 'addClass' : 'removeClass']('elfinder-cwd-wrapper-empty');
wrapper.off(scrollEvent, render).on(scrollEvent, render).trigger(scrollEvent);
// set droppable
if (!fm.cwd().write) {
wrapper.removeClass('native-droppable')
.droppable('disable')
.removeClass('ui-state-disabled'); // for old jQueryUI see https://bugs.jqueryui.com/ticket/5974
} else {
wrapper[fm.isCommandEnabled('upload')? 'addClass' : 'removeClass']('native-droppable');
wrapper.droppable(fm.isCommandEnabled('paste')? 'enable' : 'disable');
}
});
},
/**
* CWD node itself
*
* @type JQuery
**/
cwd = $(this)
.addClass('ui-helper-clearfix elfinder-cwd')
.attr('unselectable', 'on')
// fix ui.selectable bugs and add shift+click support
.on('click.'+fm.namespace, fileSelector, function(e) {
var p = this.id ? $(this) : $(this).parents('[id]:first'),
tgt = $(e.target),
prev,
next,
pl,
nl,
sib;
if (selectCheckbox && (tgt.is('input:checkbox.'+clSelChk) || tgt.hasClass('elfinder-cwd-select'))) {
e.stopPropagation();
e.preventDefault();
p.trigger(p.hasClass(clSelected) ? evtUnselect : evtSelect);
trigger();
requestAnimationFrame(function() {
tgt.prop('checked', p.hasClass(clSelected));
});
return;
}
if (cwd.data('longtap') || tgt.hasClass('elfinder-cwd-nonselect')) {
e.stopPropagation();
return;
}
if (!curClickId) {
curClickId = p.attr('id');
setTimeout(function() {
curClickId = '';
}, 500);
}
if (e.shiftKey) {
prev = p.prevAll(lastSelect || '.'+clSelected+':first');
next = p.nextAll(lastSelect || '.'+clSelected+':first');
pl = prev.length;
nl = next.length;
}
if (e.shiftKey && (pl || nl)) {
sib = pl ? p.prevUntil('#'+prev.attr('id')) : p.nextUntil('#'+next.attr('id'));
sib.add(p).trigger(evtSelect);
} else if (e.ctrlKey || e.metaKey) {
p.trigger(p.hasClass(clSelected) ? evtUnselect : evtSelect);
} else {
if (wrapper.data('touching') && p.hasClass(clSelected)) {
wrapper.data('touching', null);
fm.dblclick({file : fm.cwdId2Hash(this.id)});
return;
} else {
unselectAll({ notrigger: true });
p.trigger(evtSelect);
}
}
trigger();
})
// call fm.open()
.on('dblclick.'+fm.namespace, fileSelector, function(e) {
if (curClickId) {
var hash = fm.cwdId2Hash(curClickId);
e.stopPropagation();
if (this.id !== curClickId) {
$(this).trigger(evtUnselect);
$('#'+curClickId).trigger(evtSelect);
trigger();
}
fm.dblclick({file : hash});
}
})
// for touch device
.on('touchstart.'+fm.namespace, fileSelector, function(e) {
if (e.originalEvent.touches.length > 1) {
return;
}
var p = this.id ? $(this) : $(this).parents('[id]:first'),
tgt = $(e.target),
nodeName = e.target.nodeName,
sel;
if ((nodeName === 'INPUT' && e.target.type === 'text') || nodeName === 'TEXTAREA' || tgt.hasClass('elfinder-cwd-nonselect')) {
e.stopPropagation();
return;
}
// now name editing
if (p.find('input:text,textarea').length) {
e.stopPropagation();
e.preventDefault();
return;
}
wrapper.data('touching', {x: e.originalEvent.touches[0].pageX, y: e.originalEvent.touches[0].pageY});
if (selectCheckbox && (tgt.is('input:checkbox.'+clSelChk) || tgt.hasClass('elfinder-cwd-select'))) {
return;
}
sel = p.prevAll('.'+clSelected+':first').length +
p.nextAll('.'+clSelected+':first').length;
cwd.data('longtap', null);
if (Object.keys(selectedFiles).length
||
(list && e.target.nodeName !== 'TD')
||
(!list && this !== e.target)
) {
cwd.data('longtap', false);
p.addClass(clHover);
p.data('tmlongtap', setTimeout(function(){
// long tap
cwd.data('longtap', true);
p.trigger(evtSelect);
trigger();
fm.trigger('contextmenu', {
'type' : 'files',
'targets' : fm.selected(),
'x' : e.originalEvent.touches[0].pageX,
'y' : e.originalEvent.touches[0].pageY
});
}, 500));
}
})
.on('touchmove.'+fm.namespace+' touchend.'+fm.namespace, fileSelector, function(e) {
var tgt = $(e.target),
p;
if (selectCheckbox && (tgt.is('input:checkbox.'+clSelChk) || tgt.hasClass('elfinder-cwd-select'))) {
return;
}
if (e.target.nodeName == 'INPUT' || e.target.nodeName == 'TEXTAREA') {
e.stopPropagation();
return;
}
p = this.id ? $(this) : $(this).parents('[id]:first');
clearTimeout(p.data('tmlongtap'));
if (e.type === 'touchmove') {
wrapper.data('touching', null);
p.removeClass(clHover);
} else {
if (wrapper.data('touching') && !cwd.data('longtap') && p.hasClass(clSelected)) {
e.preventDefault();
wrapper.data('touching', null);
fm.dblclick({file : fm.cwdId2Hash(this.id)});
}
setTimeout(function() {
cwd.removeData('longtap');
}, 80);
}
})
// attach draggable
.on('mouseenter.'+fm.namespace, fileSelector, function(e) {
if (scrolling) { return; }
var $this = $(this), helper = null;
if (!mobile && !$this.data('dragRegisted') && !$this.hasClass(clTmp) && !$this.hasClass(clDraggable) && !$this.hasClass(clDisabled)) {
$this.data('dragRegisted', true);
if (!fm.isCommandEnabled('copy', fm.searchStatus.state > 1 || $this.hasClass('isroot')? fm.cwdId2Hash($this.attr('id')) : void 0)) {
return;
}
$this.on('mousedown', function(e) {
// shiftKey or altKey + drag start for HTML5 native drag function
// Note: can no use shiftKey with the Google Chrome
var metaKey = e.shiftKey || e.altKey,
disable = false;
if (metaKey && !fm.UA.IE && cwd.data('selectable')) {
// destroy jQuery-ui selectable while trigger native drag
cwd.selectable('disable').selectable('destroy').removeData('selectable');
requestAnimationFrame(function(){
cwd.selectable(selectableOption).selectable('option', {disabled: false}).selectable('refresh').data('selectable', true);
});
}
$this.removeClass('ui-state-disabled');
if (metaKey) {
$this.draggable('option', 'disabled', true).attr('draggable', 'true');
} else {
if (!$this.hasClass(clSelected)) {
if (list) {
disable = $(e.target).closest('span,tr').is('tr');
} else {
disable = $(e.target).hasClass('elfinder-cwd-file');
}
}
if (disable) {
$this.draggable('option', 'disabled', true);
} else {
$this.draggable('option', 'disabled', false)
.removeAttr('draggable')
.draggable('option', 'cursorAt', {left: 50 - parseInt($(e.currentTarget).css('margin-left')), top: 47});
}
}
})
.on('dragstart', function(e) {
var dt = e.dataTransfer || e.originalEvent.dataTransfer || null;
helper = null;
if (dt && !fm.UA.IE) {
var p = this.id ? $(this) : $(this).parents('[id]:first'),
elm = $('<span>'),
url = '',
durl = null,
murl = null,
files = [],
icon = function(f) {
var mime = f.mime, i, tmb = fm.tmb(f);
i = '<div class="elfinder-cwd-icon elfinder-cwd-icon-drag '+fm.mime2class(mime)+' ui-corner-all"/>';
if (tmb) {
i = $(i).addClass(tmb.className).css('background-image', "url('"+tmb.url+"')").get(0).outerHTML;
}
return i;
}, l, geturl = [];
p.trigger(evtSelect);
trigger();
$.each(selectedFiles, function(v){
var file = fm.file(v),
furl = file.url;
if (file && file.mime !== 'directory') {
if (!furl) {
furl = fm.url(file.hash);
} else if (furl == '1') {
geturl.push(v);
return true;
}
if (furl) {
furl = fm.convAbsUrl(furl);
files.push(v);
$('<a>').attr('href', furl).text(furl).appendTo(elm);
url += furl + "\n";
if (!durl) {
durl = file.mime + ':' + file.name + ':' + furl;
}
if (!murl) {
murl = furl + "\n" + file.name;
}
}
}
});
if (geturl.length) {
$.each(geturl, function(i, v){
var rfile = fm.file(v);
rfile.url = '';
fm.request({
data : {cmd : 'url', target : v},
notify : {type : 'url', cnt : 1},
preventDefault : true
})
.always(function(data) {
rfile.url = data.url? data.url : '1';
});
});
return false;
} else if (url) {
if (dt.setDragImage) {
helper = $('<div class="elfinder-drag-helper html5-native"></div>').append(icon(fm.file(files[0]))).appendTo($(document.body));
if ((l = files.length) > 1) {
helper.append(icon(fm.file(files[l-1])) + '<span class="elfinder-drag-num">'+l+'</span>');
}
dt.setDragImage(helper.get(0), 50, 47);
}
dt.effectAllowed = 'copyLink';
dt.setData('DownloadURL', durl);
dt.setData('text/x-moz-url', murl);
dt.setData('text/uri-list', url);
dt.setData('text/plain', url);
dt.setData('text/html', elm.html());
dt.setData('elfinderfrom', window.location.href + fm.cwd().hash);
dt.setData('elfinderfrom:' + dt.getData('elfinderfrom'), '');
} else {
return false;
}
}
})
.on('dragend', function(e){
unselectAll({ notrigger: true });
helper && helper.remove();
})
.draggable(fm.draggable);
}
})
// add hover class to selected file
.on(evtSelect, fileSelector, function(e) {
var $this = $(this),
id = fm.cwdId2Hash($this.attr('id'));
if (!selectLock && !$this.hasClass(clDisabled)) {
lastSelect = '#'+ this.id;
$this.addClass(clSelected).children().addClass(clHover).find('input:checkbox.'+clSelChk).prop('checked', true);
if (! selectedFiles[id]) {
selectedFiles[id] = true;
}
// will be selected next
selectedNext = cwd.find('[id].'+clSelected+':last').next();
}
})
// remove hover class from unselected file
.on(evtUnselect, fileSelector, function(e) {
var $this = $(this),
id = fm.cwdId2Hash($this.attr('id'));
if (!selectLock) {
$this.removeClass(clSelected).children().removeClass(clHover).find('input:checkbox.'+clSelChk).prop('checked', false);
if (cwd.hasClass('elfinder-cwd-allselected')) {
selectCheckbox && selectAllCheckbox.children('input').prop('checked', false);
cwd.removeClass('elfinder-cwd-allselected');
}
selectedFiles[id] && delete selectedFiles[id];
}
})
// disable files wich removing or moving
.on(evtDisable, fileSelector, function() {
var $this = $(this).removeClass(clHover+' '+clSelected).addClass(clDisabled),
child = $this.children(),
target = (list ? $this : child.find('div.elfinder-cwd-file-wrapper,div.elfinder-cwd-filename'));
child.removeClass(clHover+' '+clSelected);
$this.hasClass(clDroppable) && $this.droppable('disable');
target.hasClass(clDraggable) && target.draggable('disable');
})
// if any files was not removed/moved - unlock its
.on(evtEnable, fileSelector, function() {
var $this = $(this).removeClass(clDisabled),
target = list ? $this : $this.children('div.elfinder-cwd-file-wrapper,div.elfinder-cwd-filename');
$this.hasClass(clDroppable) && $this.droppable('enable');
target.hasClass(clDraggable) && target.draggable('enable');
})
.on('scrolltoview', fileSelector, function(e, data) {
scrollToView($(this), (data && typeof data.blink !== 'undefined')? data.blink : true);
})
.on('mouseenter.'+fm.namespace+' mouseleave.'+fm.namespace, fileSelector, function(e) {
var enter = (e.type === 'mouseenter');
if (enter && (scrolling || fm.UA.Mobile)) { return; }
fm.trigger('hover', {hash : fm.cwdId2Hash($(this).attr('id')), type : e.type});
$(this).toggleClass(clHover, (e.type == 'mouseenter'));
})
// for file contextmenu
.on('mouseenter.'+fm.namespace+' mouseleave.'+fm.namespace, '.elfinder-cwd-file-wrapper,.elfinder-cwd-filename', function(e) {
var enter = (e.type === 'mouseenter');
if (enter && scrolling) { return; }
$(this).closest(fileSelector).children('.elfinder-cwd-file-wrapper,.elfinder-cwd-filename').toggleClass(clActive, (e.type == 'mouseenter'));
})
.on('contextmenu.'+fm.namespace, function(e) {
var file = $(e.target).closest(fileSelector);
if (file.get(0) === e.target && !selectedFiles[fm.cwdId2Hash(file.get(0).id)]) {
return;
}
// now filename editing
if (file.find('input:text,textarea').length) {
e.stopPropagation();
return;
}
if (file.length && (e.target.nodeName != 'TD' || selectedFiles[fm.cwdId2Hash(file.get(0).id)])) {
e.stopPropagation();
e.preventDefault();
if (!file.hasClass(clDisabled) && !wrapper.data('touching')) {
if (!file.hasClass(clSelected)) {
unselectAll({ notrigger: true });
file.trigger(evtSelect);
trigger();
}
fm.trigger('contextmenu', {
'type' : 'files',
'targets' : fm.selected(),
'x' : e.pageX,
'y' : e.pageY
});
}
}
})
// unselect all on cwd click
.on('click.'+fm.namespace, function(e) {
if (e.target === this && ! cwd.data('longtap')) {
!e.shiftKey && !e.ctrlKey && !e.metaKey && unselectAll();
}
})
// prepend fake file/dir
.on('create.'+fm.namespace, function(e, f) {
var parent = list ? cwd.find('tbody') : cwd,
p = parent.find('.elfinder-cwd-parent'),
lock = f.move || false,
file = $(itemhtml(f)).addClass(clTmp),
selected = fm.selected();
if (selected.length) {
lock && fm.trigger('lockfiles', {files: selected});
} else {
unselectAll();
}
if (p.length) {
p.after(file);
} else {
parent.prepend(file);
}
setColwidth();
wrapper.scrollTop(0).scrollLeft(0);
})
// unselect all selected files
.on('unselectall', unselectAll)
.on('selectfile', function(e, id) {
$('#'+fm.cwdHash2Id(id)).trigger(evtSelect);
trigger();
})
.on('colwidth', function() {
if (list) {
cwd.find('table').css('table-layout', '')
.find('td').css('width', '');
fixTableHeader({fitWidth: true});
fm.storage('cwdColWidth', colWidth = null);
}
})
.on('iconpref', function(e, data) {
cwd.removeClass(function(i, cName) {
return (cName.match(/\belfinder-cwd-size\S+/g) || []).join(' ');
});
iconSize = data? (parseInt(data.size) || 0) : 0;
if (!list) {
if (iconSize > 0) {
cwd.addClass('elfinder-cwd-size' + iconSize);
}
if (bufferExt.renderd) {
requestAnimationFrame(function() {
itemBoxSize.icons = {};
bufferExt.hpi = null;
bottomMarkerShow(cwd, bufferExt.renderd);
wrapperRepaint();
});
}
}
})
// Change icon size with mouse wheel event
.on('onwheel' in document ? 'wheel' : 'mousewheel', function(e) {
var tm, size, delta;
if (!list && ((e.ctrlKey && !e.metaKey) || (!e.ctrlKey && e.metaKey))) {
e.stopPropagation();
e.preventDefault();
tm = cwd.data('wheelTm');
if (typeof tm !== 'undefined') {
clearTimeout(tm);
cwd.data('wheelTm', setTimeout(function() {
cwd.removeData('wheelTm');
}, 200));
} else {
cwd.data('wheelTm', false);
size = iconSize || 0;
delta = e.originalEvent.deltaY ? e.originalEvent.deltaY : -(e.originalEvent.wheelDelta);
if (delta > 0) {
if (iconSize > 0) {
size = iconSize - 1;
}
} else {
if (iconSize < options.iconsView.sizeMax) {
size = iconSize + 1;
}
}
if (size !== iconSize) {
fm.storage('iconsize', size);
cwd.trigger('iconpref', {size: size});
}
}
}
}),
wrapper = $('<div class="elfinder-cwd-wrapper"/>')
// make cwd itself droppable for folders from nav panel
.droppable(Object.assign({}, droppable, {autoDisable: false}))
.on('contextmenu.'+fm.namespace, wrapperContextMenu.contextmenu)
.on('touchstart.'+fm.namespace, wrapperContextMenu.touchstart)
.on('touchmove.'+fm.namespace+' touchend.'+fm.namespace, wrapperContextMenu.touchend)
.on('click.'+fm.namespace, wrapperContextMenu.click)
.on('scroll.'+fm.namespace, function() {
if (! scrolling) {
cwd.data('selectable') && cwd.selectable('disable');
wrapper.trigger(scrollStartEvent);
}
scrolling = true;
bufferExt.scrtm && cancelAnimationFrame(bufferExt.scrtm);
if (bufferExt.scrtm && Math.abs((bufferExt.scrolltop || 0) - (bufferExt.scrolltop = (this.scrollTop || $(this).scrollTop()))) < 5) {
bufferExt.scrtm = 0;
wrapper.trigger(scrollEvent);
}
bufferExt.scrtm = requestAnimationFrame(function() {
bufferExt.scrtm = 0;
wrapper.trigger(scrollEvent);
});
})
.on(scrollEvent, function() {
scrolling = false;
wrapperRepaint();
}),
bottomMarker = $('<div>&nbsp;</div>')
.css({position: 'absolute', width: '1px', height: '1px'})
.hide(),
selectAllCheckbox = selectCheckbox? $('<div class="elfinder-cwd-selectall"><input type="checkbox"/></div>')
.attr('title', fm.i18n('selectall'))
.on('touchstart mousedown click', function(e) {
e.stopPropagation();
e.preventDefault();
if ($(this).data('pending') || e.type === 'click') {
return false;
}
selectAllCheckbox.data('pending', true);
if (cwd.hasClass('elfinder-cwd-allselected')) {
selectAllCheckbox.find('input').prop('checked', false);
requestAnimationFrame(function() {
unselectAll();
});
} else {
selectAll();
}
}) : $(),
restm = null,
resize = function(init) {
var initHeight = function() {
if (typeof bufferExt.renderd !== 'undefined') {
var h = 0;
wrapper.siblings('div.elfinder-panel:visible').each(function() {
h += $(this).outerHeight(true);
});
wrapper.height(wz.height() - h - wrapper._padding);
}
};
init && initHeight();
restm && cancelAnimationFrame(restm);
restm = requestAnimationFrame(function(){
!init && initHeight();
var wph, cwdoh;
// fix cwd height if it less then wrapper
cwd.css('height', 'auto');
wph = wrapper[0].clientHeight - parseInt(wrapper.css('padding-top')) - parseInt(wrapper.css('padding-bottom')) - parseInt(cwd.css('margin-top')),
cwdoh = cwd.outerHeight(true);
if (cwdoh < wph) {
cwd.height(wph);
}
});
list && ! colResizing && (init? wrapper.trigger('resize.fixheader') : fixTableHeader());
wrapperRepaint();
},
// elfinder node
parent = $(this).parent().on('resize', resize),
// workzone node
wz = parent.children('.elfinder-workzone').append(wrapper.append(this).append(bottomMarker)),
// message board
mBoard = $('<div class="elfinder-cwd-message-board"/>').insertAfter(cwd),
// Volume expires
vExpires = $('<div class="elfinder-cwd-expires" />'),
vExpiresTm,
showVolumeExpires = function() {
var remain, sec, int;
vExpiresTm && clearTimeout(vExpiresTm);
if (curVolId && fm.volumeExpires[curVolId]) {
sec = fm.volumeExpires[curVolId] - ((+new Date()) / 1000);
int = (sec % 60) + 0.1;
remain = Math.floor(sec / 60);
vExpires.html(fm.i18n(['minsLeft', remain])).show();
if (remain) {
vExpiresTm = setTimeout(showVolumeExpires, int * 1000);
}
}
},
// each item box size
itemBoxSize = {
icons : {},
list : {}
},
// has UI tree
hasUiTree,
// Icon size of icons view
iconSize,
// Current volume id
curVolId,
winScrTm;
// IE < 11 not support CSS `pointer-events: none`
if (!fm.UA.ltIE10) {
mBoard.append($('<div class="elfinder-cwd-trash" />').html(fm.i18n('volume_Trash')))
.append(vExpires);
}
// setup by options
replacement = Object.assign(replacement, options.replacement || {});
try {
colWidth = fm.storage('cwdColWidth')? fm.storage('cwdColWidth') : null;
} catch(e) {
colWidth = null;
}
// setup costomCols
fm.bind('columnpref', function(e) {
var opts = e.data || {};
if (customCols = fm.storage('cwdCols')) {
customCols = $.grep(customCols, function(n) {
return (options.listView.columns.indexOf(n) !== -1)? true : false;
});
if (options.listView.columns.length > customCols.length) {
$.each(options.listView.columns, function(i, n) {
if (customCols.indexOf(n) === -1) {
customCols.push(n);
}
});
}
} else {
customCols = options.listView.columns;
}
// column names array that hidden
var columnhides = fm.storage('columnhides') || null;
if (columnhides && Object.keys(columnhides).length)
customCols = $.grep(customCols, function(n) {
return columnhides[n]? false : true;
});
// make template with customCols
templates.row = makeTemplateRow();
// repaint if need it
list && opts.repaint && content();
}).trigger('columnpref');
if (mobile) {
// for iOS5 bug
$('body').on('touchstart touchmove touchend', function(e){});
}
selectCheckbox && cwd.addClass('elfinder-has-checkbox');
$(window).on('scroll.'+fm.namespace, function() {
winScrTm && cancelAnimationFrame(winScrTm);
winScrTm = requestAnimationFrame(function() {
wrapper.trigger(scrollEvent);
});
});
$(document).on('keydown.'+fm.namespace, function(e) {
if (e.keyCode == $.ui.keyCode.ESCAPE) {
if (! fm.getUI().find('.ui-widget:visible').length) {
unselectAll();
}
}
});
fm
.one('init', function(){
var style = document.createElement('style'),
sheet, node, base, resizeTm, iconSize, i = 0;
if (document.head) {
document.head.appendChild(style);
sheet = style.sheet;
sheet.insertRule('.elfinder-cwd-wrapper-empty .elfinder-cwd:not(.elfinder-table-header-sticky):after{ content:"'+fm.i18n('emptyFolder')+'" }', i++);
sheet.insertRule('.elfinder-cwd-wrapper-empty .native-droppable .elfinder-cwd:not(.elfinder-table-header-sticky):after{ content:"'+fm.i18n('emptyFolder'+(mobile? 'LTap' : 'Drop'))+'" }', i++);
sheet.insertRule('.elfinder-cwd-wrapper-empty .ui-droppable-disabled .elfinder-cwd:not(.elfinder-table-header-sticky):after{ content:"'+fm.i18n('emptyFolder')+'" }', i++);
sheet.insertRule('.elfinder-cwd-wrapper-empty.elfinder-search-result .elfinder-cwd:not(.elfinder-table-header-sticky):after{ content:"'+fm.i18n('emptySearch')+'" }', i++);
sheet.insertRule('.elfinder-cwd-wrapper-empty.elfinder-search-result.elfinder-incsearch-result .elfinder-cwd:not(.elfinder-table-header-sticky):after{ content:"'+fm.i18n('emptyIncSearch')+'" }', i++);
sheet.insertRule('.elfinder-cwd-wrapper-empty.elfinder-search-result.elfinder-letsearch-result .elfinder-cwd:not(.elfinder-table-header-sticky):after{ content:"'+fm.i18n('emptyLetSearch')+'" }', i++);
}
if (iconSize = fm.storage('iconsize') || 0) {
cwd.trigger('iconpref', {size: iconSize});
}
if (! mobile) {
fm.one('open', function() {
sheet && fm.zIndex && sheet.insertRule('.ui-selectable-helper{z-index:'+fm.zIndex+';}', i++);
});
base = $('<div style="position:absolute"/>');
node = fm.getUI();
node.on('resize', function(e, data) {
var offset;
e.preventDefault();
e.stopPropagation();
if (data && data.fullscreen) {
offset = node.offset();
if (data.fullscreen === 'on') {
base.css({top:offset.top * -1 , left:offset.left * -1 }).appendTo(node);
selectableOption.appendTo = base;
} else {
base.detach();
selectableOption.appendTo = 'body';
}
cwd.data('selectable') && cwd.selectable('option', {appendTo : selectableOption.appendTo});
}
});
}
hasUiTree = fm.getUI('tree').length;
})
.bind('enable', function() {
resize();
})
.bind('request.open', function() {
bufferExt.getTmbs = [];
})
.one('open', function() {
if (fm.maxTargets) {
tmbNum = Math.min(fm.maxTargets, tmbNum);
}
})
.bind('open add remove searchend', function() {
var phash = fm.cwd().hash,
type = this.type;
if (type === 'open' || type === 'searchend' || fm.searchStatus.state < 2) {
cwdHashes = $.map(fm.files(phash), function(f) { return f.hash; });
fm.trigger('cwdhasheschange', cwdHashes);
}
if (type === 'open') {
var inTrash = function() {
var isIn = false;
$.each(cwdParents, function(i, h) {
if (fm.trashes[h]) {
isIn = true;
return false;
}
});
return isIn;
},
req = phash?
(! fm.file(phash) || hasUiTree?
(! hasUiTree?
fm.request({
data: {
cmd : 'parents',
target : fm.cwd().hash
},
preventFail : true
}) : (function() {
var dfd = $.Deferred();
fm.one('treesync', function(e) {
e.data.always(function() {
dfd.resolve();
});
});
return dfd;
})()
) : null
) : null,
cwdObj = fm.cwd();
// add/remove volume id class
if (cwdObj.volumeid !== curVolId) {
vExpires.empty().hide();
if (curVolId) {
wrapper.removeClass('elfinder-cwd-wrapper-' + curVolId);
}
curVolId = cwdObj.volumeid;
showVolumeExpires();
wrapper.addClass('elfinder-cwd-wrapper-' + curVolId);
}
// add/remove trash class
$.when(req).done(function() {
cwdParents = fm.parents(cwdObj.hash);
wrapper[inTrash()? 'addClass':'removeClass']('elfinder-cwd-wrapper-trash');
});
incHashes = void 0;
unselectAll({ notrigger: true });
content();
}
})
.bind('search', function(e) {
cwdHashes = $.map(e.data.files, function(f) { return f.hash; });
fm.trigger('cwdhasheschange', cwdHashes);
incHashes = void 0;
fm.searchStatus.ininc = false;
content();
fm.autoSync('stop');
})
.bind('searchend', function(e) {
if (query || incHashes) {
query = '';
if (incHashes) {
fm.trigger('incsearchend', e.data);
} else {
if (!e.data || !e.data.noupdate) {
content();
}
}
}
fm.autoSync();
})
.bind('searchstart', function(e) {
unselectAll();
query = e.data.query;
})
.bind('incsearchstart', function(e) {
selectedFiles = {};
fm.lazy(function() {
// incremental search
var regex, q, fst = '';
q = query = e.data.query || '';
if (q) {
if (q.substr(0,1) === '/') {
q = q.substr(1);
fst = '^';
}
regex = new RegExp(fst + q.replace(/([\\*\;\.\?\[\]\{\}\(\)\^\$\-\|])/g, '\\$1'), 'i');
incHashes = $.grep(cwdHashes, function(hash) {
var file = fm.file(hash);
return (file && (file.name.match(regex) || (file.i18 && file.i18.match(regex))))? true : false;
});
fm.trigger('incsearch', { hashes: incHashes, query: q })
.searchStatus.ininc = true;
content();
fm.autoSync('stop');
} else {
fm.trigger('incsearchend');
}
});
})
.bind('incsearchend', function(e) {
query = '';
fm.searchStatus.ininc = false;
incHashes = void 0;
if (!e.data || !e.data.noupdate) {
content();
}
fm.autoSync();
})
.bind('sortchange', function() {
var lastScrollLeft = wrapper.scrollLeft(),
allsel = cwd.hasClass('elfinder-cwd-allselected');
content();
fm.one('cwdrender', function() {
wrapper.scrollLeft(lastScrollLeft);
if (allsel) {
selectedFiles = fm.arrayFlip(incHashes || cwdHashes, true);
}
(allsel || Object.keys(selectedFiles).length) && trigger();
});
})
.bind('viewchange', function() {
var l = fm.storage('view') == 'list',
allsel = cwd.hasClass('elfinder-cwd-allselected');
if (l != list) {
list = l;
fm.viewType = list? 'list' : 'icons';
if (iconSize) {
fm.one('cwdinit', function() {
cwd.trigger('iconpref', {size: iconSize});
});
}
content();
resize();
if (allsel) {
cwd.addClass('elfinder-cwd-allselected');
selectAllCheckbox.find('input').prop('checked', true);
}
Object.keys(selectedFiles).length && trigger();
}
})
.bind('wzresize', function() {
var place = list ? cwd.find('tbody') : cwd,
cwdOffset;
resize(true);
if (bufferExt.hpi) {
bottomMarkerShow(place, place.find('[id]').length);
}
cwdOffset = cwd.offset();
wz.data('rectangle', Object.assign(
{
width: wz.width(),
height: wz.height(),
cwdEdge: (fm.direction === 'ltr')? cwdOffset.left : cwdOffset.left + cwd.width()
},
wz.offset())
);
bufferExt.itemH = (list? place.find('tr:first') : place.find('[id]:first')).outerHeight(true);
})
.bind('changeclipboard', function(e) {
clipCuts = {};
if (e.data && e.data.clipboard && e.data.clipboard.length) {
$.each(e.data.clipboard, function(i, f) {
if (f.cut) {
clipCuts[f.hash] = true;
}
});
}
})
.bind('resMixinMake', function() {
setColwidth();
})
.bind('tmbreload', function(e) {
var imgs = {},
files = (e.data && e.data.files)? e.data.files : null;
$.each(files, function(i, f) {
if (f.tmb && f.tmb != '1') {
imgs[f.hash] = f.tmb;
}
});
if (Object.keys(imgs).length) {
attachThumbnails(imgs, true);
}
})
.add(function(e) {
var regex = query? new RegExp(query.replace(/([\\*\;\.\?\[\]\{\}\(\)\^\$\-\|])/g, '\\$1'), 'i') : null,
mime = fm.searchStatus.mime,
inSearch = fm.searchStatus.state > 1,
phash = inSearch && fm.searchStatus.target? fm.searchStatus.target : fm.cwd().hash,
curPath = fm.path(phash),
inTarget = function(f) {
var res, parents, path;
res = (f.phash === phash);
if (!res && inSearch) {
path = f.path || fm.path(f.hash);
res = (curPath && path.indexOf(curPath) === 0);
if (! res && fm.searchStatus.mixed) {
res = $.grep(fm.searchStatus.mixed, function(vid) { return f.hash.indexOf(vid) === 0? true : false; }).length? true : false;
}
}
if (res && inSearch) {
if (mime) {
res = (f.mime.indexOf(mime) === 0);
} else {
res = (f.name.match(regex) || (f.i18 && f.i18.match(regex)))? true : false;
}
}
return res;
},
files = $.grep(e.data.added || [], function(f) { return inTarget(f)? true : false ;});
add(files);
if (fm.searchStatus.state === 2) {
$.each(files, function(i, f) {
if ($.inArray(f.hash, cwdHashes) === -1) {
cwdHashes.push(f.hash);
}
});
fm.trigger('cwdhasheschange', cwdHashes);
}
list && resize();
wrapper.trigger(scrollEvent);
})
.change(function(e) {
var phash = fm.cwd().hash,
sel = fm.selected(),
files, added;
if (query) {
$.each(e.data.changed || [], function(i, file) {
if ($('#'+fm.cwdHash2Id(file.hash)).length) {
remove([file.hash]);
add([file], 'change');
$.inArray(file.hash, sel) !== -1 && selectFile(file.hash);
added = true;
}
});
} else {
$.each($.grep(e.data.changed || [], function(f) { return f.phash == phash ? true : false; }), function(i, file) {
if ($('#'+fm.cwdHash2Id(file.hash)).length) {
remove([file.hash]);
add([file], 'change');
$.inArray(file.hash, sel) !== -1 && selectFile(file.hash);
added = true;
}
});
}
if (added) {
fm.trigger('cwdhasheschange', cwdHashes);
list && resize();
wrapper.trigger(scrollEvent);
}
trigger();
})
.remove(function(e) {
var place = list ? cwd.find('tbody') : cwd;
remove(e.data.removed || []);
trigger();
if (buffer.length < 1 && place.children(fileSelector).length < 1) {
wz.addClass('elfinder-cwd-wrapper-empty');
selectCheckbox && selectAllCheckbox.find('input').prop('checked', false);
bottomMarker.hide();
wrapper.off(scrollEvent, render);
resize();
} else {
bottomMarkerShow(place);
wrapper.trigger(scrollEvent);
}
})
// select dragged file if no selected, disable selectable
.dragstart(function(e) {
var target = $(e.data.target),
oe = e.data.originalEvent;
if (target.hasClass(clFile)) {
if (!target.hasClass(clSelected)) {
!(oe.ctrlKey || oe.metaKey || oe.shiftKey) && unselectAll({ notrigger: true });
target.trigger(evtSelect);
trigger();
}
}
cwd.removeClass(clDisabled).data('selectable') && cwd.selectable('disable');
selectLock = true;
})
// enable selectable
.dragstop(function() {
cwd.data('selectable') && cwd.selectable('enable');
selectLock = false;
})
.bind('lockfiles unlockfiles selectfiles unselectfiles', function(e) {
var events = {
lockfiles : evtDisable ,
unlockfiles : evtEnable ,
selectfiles : evtSelect,
unselectfiles : evtUnselect },
event = events[e.type],
files = e.data.files || [],
l = files.length,
helper = e.data.helper || $(),
parents, ctr, add;
if (l > 0) {
parents = fm.parents(files[0]);
}
if (event === evtSelect || event === evtUnselect) {
add = (event === evtSelect),
$.each(files, function(i, hash) {
var all = cwd.hasClass('elfinder-cwd-allselected');
if (! selectedFiles[hash]) {
add && (selectedFiles[hash] = true);
} else {
if (all) {
selectCheckbox && selectAllCheckbox.children('input').prop('checked', false);
cwd.removeClass('elfinder-cwd-allselected');
all = false;
}
! add && delete selectedFiles[hash];
}
});
}
if (!helper.data('locked')) {
while (l--) {
try {
$('#'+fm.cwdHash2Id(files[l])).trigger(event);
} catch(e) {}
}
! e.data.inselect && trigger();
}
if (wrapper.data('dropover') && parents.indexOf(wrapper.data('dropover')) !== -1) {
ctr = e.type !== 'lockfiles';
helper.toggleClass('elfinder-drag-helper-plus', ctr);
wrapper.toggleClass(clDropActive, ctr);
}
})
// select new files after some actions
.bind('mkdir mkfile duplicate upload rename archive extract paste multiupload', function(e) {
if (e.type == 'upload' && e.data._multiupload) return;
var phash = fm.cwd().hash, files;
unselectAll({ notrigger: true });
$.each((e.data.added || []).concat(e.data.changed || []), function(i, file) {
file && file.phash == phash && selectFile(file.hash);
});
trigger();
})
.shortcut({
pattern :'ctrl+a',
description : 'selectall',
callback : selectAll
})
.shortcut({
pattern :'ctrl+shift+i',
description : 'selectinvert',
callback : selectInvert
})
.shortcut({
pattern : 'left right up down shift+left shift+right shift+up shift+down',
description : 'selectfiles',
type : 'keydown' , //fm.UA.Firefox || fm.UA.Opera ? 'keypress' : 'keydown',
callback : function(e) { select(e.keyCode, e.shiftKey); }
})
.shortcut({
pattern : 'home',
description : 'selectffile',
callback : function(e) {
unselectAll({ notrigger: true });
scrollToView(cwd.find('[id]:first').trigger(evtSelect));
trigger();
}
})
.shortcut({
pattern : 'end',
description : 'selectlfile',
callback : function(e) {
unselectAll({ notrigger: true });
scrollToView(cwd.find('[id]:last').trigger(evtSelect)) ;
trigger();
}
})
.shortcut({
pattern : 'page_up',
description : 'pageTurning',
callback : function(e) {
if (bufferExt.itemH) {
wrapper.scrollTop(
Math.round(
wrapper.scrollTop()
- (Math.floor((wrapper.height() + (list? bufferExt.itemH * -1 : 16)) / bufferExt.itemH)) * bufferExt.itemH
)
);
}
}
}).shortcut({
pattern : 'page_down',
description : 'pageTurning',
callback : function(e) {
if (bufferExt.itemH) {
wrapper.scrollTop(
Math.round(
wrapper.scrollTop()
+ (Math.floor((wrapper.height() + (list? bufferExt.itemH * -1 : 16)) / bufferExt.itemH)) * bufferExt.itemH
)
);
}
}
});
});
// fm.timeEnd('cwdLoad')
return this;
};
/*
* File: /js/ui/dialog.js
*/
/**
* @class elFinder dialog
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfinderdialog = function(opts, fm) {
var platformWin = (window.navigator.platform.indexOf('Win') != -1),
delta = {},
syncSize = { enabled: false, width: false, height: false, defaultSize: null },
fitSize = function(dialog) {
var opts, node;
if (syncSize.enabled) {
node = fm.options.dialogContained? elfNode : $(window);
opts = {
maxWidth : syncSize.width? node.width() - delta.width : null,
maxHeight: syncSize.height? node.height() - delta.height : null
};
Object.assign(restoreStyle, opts);
dialog.css(opts).trigger('resize');
if (dialog.data('hasResizable') && (dialog.resizable('option', 'maxWidth') < opts.maxWidth || dialog.resizable('option', 'maxHeight') < opts.maxHeight)) {
dialog.resizable('option', opts);
}
}
},
syncFunc = function(e) {
var dialog = e.data;
syncTm && cancelAnimationFrame(syncTm);
syncTm = requestAnimationFrame(function() {
var opts, offset;
if (syncSize.enabled) {
fitSize(dialog);
}
});
},
checkEditing = function() {
var cldialog = 'elfinder-dialog',
dialogs = elfNode.children('.' + cldialog + '.' + fm.res('class', 'editing') + ':visible');
fm[dialogs.length? 'disable' : 'enable']();
},
propagationEvents = {},
syncTm, dialog, elfNode, restoreStyle;
if (fm && fm.ui) {
elfNode = fm.getUI();
} else {
elfNode = this.closest('.elfinder');
if (! fm) {
fm = elfNode.elfinder('instance');
}
}
if (typeof opts === 'string') {
if ((dialog = this.closest('.ui-dialog')).length) {
if (opts === 'open') {
if (dialog.css('display') === 'none') {
// Need dialog.show() and hide() to detect elements size in open() callbacks
dialog.trigger('posinit').show().trigger('open').hide();
dialog.fadeIn(120, function() {
fm.trigger('dialogopened', {dialog: dialog});
});
}
} else if (opts === 'close' || opts === 'destroy') {
dialog.stop(true);
if (dialog.is(':visible') || elfNode.is(':hidden')) {
dialog.trigger('close');
fm.trigger('dialogclosed', {dialog: dialog});
}
if (opts === 'destroy') {
dialog.remove();
fm.trigger('dialogremoved', {dialog: dialog});
}
} else if (opts === 'toTop') {
dialog.trigger('totop');
fm.trigger('dialogtotoped', {dialog: dialog});
} else if (opts === 'posInit') {
dialog.trigger('posinit');
fm.trigger('dialogposinited', {dialog: dialog});
} else if (opts === 'tabstopsInit') {
dialog.trigger('tabstopsInit');
fm.trigger('dialogtabstopsinited', {dialog: dialog});
} else if (opts === 'checkEditing') {
checkEditing();
}
}
return this;
}
opts = Object.assign({}, $.fn.elfinderdialog.defaults, opts);
if (opts.allowMinimize && opts.allowMinimize === 'auto') {
opts.allowMinimize = this.find('textarea,input').length? true : false;
}
opts.openMaximized = opts.allowMinimize && opts.openMaximized;
if (opts.headerBtnPos && opts.headerBtnPos === 'auto') {
opts.headerBtnPos = platformWin? 'right' : 'left';
}
if (opts.headerBtnOrder && opts.headerBtnOrder === 'auto') {
opts.headerBtnOrder = platformWin? 'close:maximize:minimize' : 'close:minimize:maximize';
}
if (opts.modal && opts.allowMinimize) {
opts.allowMinimize = false;
}
if (fm.options.dialogContained) {
syncSize.width = syncSize.height = syncSize.enabled = true;
} else {
syncSize.width = (opts.maxWidth === 'window');
syncSize.height = (opts.maxHeight === 'window');
if (syncSize.width || syncSize.height) {
syncSize.enabled = true;
}
}
propagationEvents = fm.arrayFlip(opts.propagationEvents, true);
this.filter(':not(.ui-dialog-content)').each(function() {
var self = $(this).addClass('ui-dialog-content ui-widget-content'),
clactive = 'elfinder-dialog-active',
cldialog = 'elfinder-dialog',
clnotify = 'elfinder-dialog-notify',
clhover = 'ui-state-hover',
cltabstop = 'elfinder-tabstop',
cl1stfocus = 'elfinder-focus',
clmodal = 'elfinder-dialog-modal',
id = parseInt(Math.random()*1000000),
titlebar = $('<div class="ui-dialog-titlebar ui-widget-header ui-corner-top ui-helper-clearfix"><span class="elfinder-dialog-title">'+opts.title+'</span></div>'),
buttonset = $('<div class="ui-dialog-buttonset"/>'),
buttonpane = $('<div class=" ui-helper-clearfix ui-dialog-buttonpane ui-widget-content"/>')
.append(buttonset),
btnWidth = 0,
btnCnt = 0,
tabstops = $(),
evCover = $('<div style="width:100%;height:100%;position:absolute;top:0px;left:0px;"/>').hide(),
numberToTel = function() {
if (opts.optimizeNumber) {
dialog.find('input[type=number]').each(function() {
$(this).attr('inputmode', 'numeric');
$(this).attr('pattern', '[0-9]*');
});
}
},
tabstopsInit = function() {
tabstops = dialog.find('.'+cltabstop);
if (tabstops.length) {
tabstops.attr('tabindex', '-1');
if (! tabstops.filter('.'+cl1stfocus).length) {
buttonset.children('.'+cltabstop+':'+(platformWin? 'first' : 'last')).addClass(cl1stfocus);
}
}
},
tabstopNext = function(cur) {
var elms = tabstops.filter(':visible:enabled'),
node = cur? null : elms.filter('.'+cl1stfocus+':first');
if (! node || ! node.length) {
node = elms.first();
}
if (cur) {
$.each(elms, function(i, elm) {
if (elm === cur && elms[i+1]) {
node = elms.eq(i+1);
return false;
}
});
}
return node;
},
tabstopPrev = function(cur) {
var elms = tabstops.filter(':visible:enabled'),
node = elms.last();
$.each(elms, function(i, elm) {
if (elm === cur && elms[i-1]) {
node = elms.eq(i-1);
return false;
}
});
return node;
},
makeHeaderBtn = function() {
$.each(opts.headerBtnOrder.split(':').reverse(), function(i, v) {
headerBtns[v] && headerBtns[v]();
});
if (platformWin) {
titlebar.children('.elfinder-titlebar-button').addClass('elfinder-titlebar-button-right');
}
},
headerBtns = {
close: function() {
titlebar.prepend($('<span class="ui-widget-header ui-dialog-titlebar-close ui-corner-all elfinder-titlebar-button"><span class="ui-icon ui-icon-closethick"/></span>')
.on('mousedown', function(e) {
e.preventDefault();
e.stopPropagation();
self.elfinderdialog('close');
})
);
},
maximize: function() {
if (opts.allowMaximize) {
dialog.on('resize', function(e, data) {
var full, elm;
e.preventDefault();
e.stopPropagation();
if (data && data.maximize) {
elm = titlebar.find('.elfinder-titlebar-full');
full = (data.maximize === 'on');
elm.children('span.ui-icon')
.toggleClass('ui-icon-plusthick', ! full)
.toggleClass('ui-icon-arrowreturnthick-1-s', full);
if (full) {
try {
dialog.hasClass('ui-draggable') && dialog.draggable('disable');
dialog.hasClass('ui-resizable') && dialog.resizable('disable');
} catch(e) {}
self.css('width', '100%').css('height', dialog.height() - dialog.children('.ui-dialog-titlebar').outerHeight(true) - buttonpane.outerHeight(true));
} else {
self.attr('style', elm.data('style'));
elm.removeData('style');
posCheck();
try {
dialog.hasClass('ui-draggable') && dialog.draggable('enable');
dialog.hasClass('ui-resizable') && dialog.resizable('enable');
} catch(e) {}
}
dialog.trigger('resize', {init: true});
}
});
titlebar.prepend($('<span class="ui-widget-header ui-corner-all elfinder-titlebar-button elfinder-titlebar-full"><span class="ui-icon ui-icon-plusthick"/></span>')
.on('mousedown', function(e) {
var elm = $(this);
e.preventDefault();
e.stopPropagation();
if (!dialog.hasClass('elfinder-maximized') && typeof elm.data('style') === 'undefined') {
self.height(self.height());
elm.data('style', self.attr('style') || '');
}
fm.toggleMaximize(dialog);
typeof(opts.maximize) === 'function' && opts.maximize.call(self[0]);
})
);
}
},
minimize: function() {
var btn, mnode, doffset;
if (opts.allowMinimize) {
btn = $('<span class="ui-widget-header ui-corner-all elfinder-titlebar-button elfinder-titlebar-minimize"><span class="ui-icon ui-icon-minusthick"/></span>')
.on('mousedown', function(e) {
var $this = $(this),
tray = fm.getUI('bottomtray'),
dumStyle = { width: 70, height: 24 },
dum = $('<div/>').css(dumStyle).addClass(dialog.get(0).className + ' elfinder-dialog-minimized'),
pos = {};
e.preventDefault();
e.stopPropagation();
if (!dialog.data('minimized')) {
// minimize
doffset = dialog.data('minimized', true).position();
mnode = dialog.clone().on('mousedown', function() {
$this.trigger('mousedown');
}).removeClass('ui-draggable ui-resizable elfinder-frontmost');
tray.append(dum);
Object.assign(pos, dum.offset(), dumStyle);
dum.remove();
mnode.height(dialog.height()).children('.ui-dialog-content:first').empty();
fm.toHide(dialog.before(mnode));
mnode.children('.ui-dialog-content:first,.ui-dialog-buttonpane,.ui-resizable-handle').remove();
mnode.find('.elfinder-titlebar-minimize,.elfinder-titlebar-full').remove();
mnode.find('.ui-dialog-titlebar-close').on('mousedown', function(e) {
e.stopPropagation();
e.preventDefault();
mnode.remove();
dialog.show();
self.elfinderdialog('close');
});
mnode.animate(pos, function() {
mnode.attr('style', '')
.css({ maxWidth: dialog.width() })
.addClass('elfinder-dialog-minimized')
.appendTo(tray);
checkEditing();
typeof(opts.minimize) === 'function' && opts.minimize.call(self[0]);
});
} else {
//restore
dialog.removeData('minimized').before(mnode.css(Object.assign({'position': 'absolute'}, mnode.offset())));
fm.toFront(mnode);
mnode.animate(Object.assign({ width: dialog.width(), height: dialog.height() }, doffset), function() {
dialog.show();
fm.toFront(dialog);
mnode.remove();
posCheck();
checkEditing();
dialog.trigger('resize', {init: true});
typeof(opts.minimize) === 'function' && opts.minimize.call(self[0]);
});
}
});
titlebar.on('dblclick', function(e) {
$(this).children('.elfinder-titlebar-minimize').trigger('mousedown');
}).prepend(btn);
dialog.on('togleminimize', function() {
btn.trigger('mousedown');
});
}
}
},
dialog = $('<div class="ui-front ui-dialog ui-widget ui-widget-content ui-corner-all ui-draggable std42-dialog touch-punch '+cldialog+' '+opts.cssClass+'"/>')
.hide()
.append(self)
.appendTo(elfNode)
.draggable({
containment : fm.options.dialogContained? elfNode : null,
handle : '.ui-dialog-titlebar',
start : function() {
evCover.show();
},
drag : function(e, ui) {
var top = ui.offset.top,
left = ui.offset.left;
if (top < 0) {
ui.position.top = ui.position.top - top;
}
if (left < 0) {
ui.position.left = ui.position.left - left;
}
if (fm.options.dialogContained) {
ui.position.top < 0 && (ui.position.top = 0);
ui.position.left < 0 && (ui.position.left = 0);
}
},
stop : function(e, ui) {
evCover.hide();
dialog.css({height : opts.height});
self.data('draged', true);
}
})
.css({
width : opts.width,
height : opts.height,
minWidth : opts.minWidth,
minHeight : opts.minHeight,
maxWidth : opts.maxWidth,
maxHeight : opts.maxHeight
})
.on('touchstart touchmove touchend click dblclick mouseup mouseenter mouseleave mouseout mouseover mousemove', function(e) {
// stopPropagation of user action events
!propagationEvents[e.type] && e.stopPropagation();
})
.on('mousedown', function(e) {
!propagationEvents[e.type] && e.stopPropagation();
requestAnimationFrame(function() {
if (dialog.is(':visible') && !dialog.hasClass('elfinder-frontmost')) {
toFocusNode = $(':focus');
if (!toFocusNode.length) {
toFocusNode = void(0);
}
dialog.trigger('totop');
}
});
})
.on('open', function() {
dialog.data('margin-y', self.outerHeight(true) - self.height());
if (syncSize.enabled) {
if (opts.height && opts.height !== 'auto') {
dialog.trigger('resize', {init: true});
}
if (!syncSize.defaultSize) {
syncSize.defaultSize = { width: self.width(), height: self.height() };
}
fitSize(dialog);
dialog.trigger('resize').trigger('posinit');
elfNode.on('resize.'+fm.namespace, dialog, syncFunc);
}
if (!dialog.hasClass(clnotify)) {
elfNode.children('.'+cldialog+':visible:not(.'+clnotify+')').each(function() {
var d = $(this),
top = parseInt(d.css('top')),
left = parseInt(d.css('left')),
_top = parseInt(dialog.css('top')),
_left = parseInt(dialog.css('left')),
ct = Math.abs(top - _top) < 10,
cl = Math.abs(left - _left) < 10;
if (d[0] != dialog[0] && (ct || cl)) {
dialog.css({
top : ct ? (top + 10) : _top,
left : cl ? (left + 10) : _left
});
}
});
}
if (dialog.data('modal')) {
dialog.addClass(clmodal);
fm.getUI('overlay').elfinderoverlay('show');
}
dialog.trigger('totop');
opts.openMaximized && fm.toggleMaximize(dialog);
fm.trigger('dialogopen', {dialog: dialog});
typeof(opts.open) == 'function' && $.proxy(opts.open, self[0])();
if (opts.closeOnEscape) {
$(document).on('keydown.'+id, function(e) {
if (e.keyCode == $.ui.keyCode.ESCAPE && dialog.hasClass('elfinder-frontmost')) {
self.elfinderdialog('close');
}
});
}
dialog.hasClass(fm.res('class', 'editing')) && checkEditing();
})
.on('close', function(e) {
var dialogs, dfd;
if (opts.beforeclose && typeof opts.beforeclose === 'function') {
dfd = opts.beforeclose();
if (!dfd || !dfd.promise) {
dfd = !dfd? $.Deferred().reject() : $.Deferred().resolve();
}
} else {
dfd = $.Deferred().resolve();
}
dfd.done(function() {
syncSize.enabled && elfNode.off('resize.'+fm.namespace, syncFunc);
if (opts.closeOnEscape) {
$(document).off('keyup.'+id);
}
if (opts.allowMaximize) {
fm.toggleMaximize(dialog, false);
}
fm.toHide(dialog);
dialog.data('modal') && fm.getUI('overlay').elfinderoverlay('hide');
if (typeof(opts.close) == 'function') {
$.proxy(opts.close, self[0])();
}
if (opts.destroyOnClose && dialog.parent().length) {
dialog.hide().remove();
}
// get focus to next dialog
dialogs = elfNode.children('.'+cldialog+':visible');
dialog.hasClass(fm.res('class', 'editing')) && checkEditing();
});
})
.on('totop frontmost', function() {
var s = fm.storage('autoFocusDialog');
dialog.data('focusOnMouseOver', s? (s > 0) : fm.options.uiOptions.dialog.focusOnMouseOver);
if (dialog.data('minimized')) {
titlebar.children('.elfinder-titlebar-minimize').trigger('mousedown');
}
if (!dialog.data('modal') && fm.getUI('overlay').is(':visible')) {
fm.getUI('overlay').before(dialog);
} else {
fm.toFront(dialog);
}
elfNode.children('.'+cldialog+':not(.'+clmodal+')').removeClass(clactive);
dialog.addClass(clactive);
! fm.UA.Mobile && (toFocusNode || tabstopNext()).trigger('focus');
toFocusNode = void(0);
})
.on('posinit', function() {
var css = opts.position,
nodeOffset, minTop, minLeft, outerSize, win, winSize, nodeFull;
if (dialog.hasClass('elfinder-maximized')) {
return;
}
if (! css && ! dialog.data('resizing')) {
nodeFull = elfNode.hasClass('elfinder-fullscreen');
dialog.css(nodeFull? {
maxWidth : '100%',
maxHeight : '100%',
overflow : 'auto'
} : restoreStyle);
if (fm.UA.Mobile && !nodeFull && dialog.data('rotated') === fm.UA.Rotated) {
return;
}
dialog.data('rotated', fm.UA.Rotated);
win = $(window);
nodeOffset = elfNode.offset();
outerSize = {
width : dialog.outerWidth(true),
height: dialog.outerHeight(true)
};
outerSize.right = nodeOffset.left + outerSize.width;
outerSize.bottom = nodeOffset.top + outerSize.height;
winSize = {
scrLeft: win.scrollLeft(),
scrTop : win.scrollTop(),
width : win.width(),
height : win.height()
};
winSize.right = winSize.scrLeft + winSize.width;
winSize.bottom = winSize.scrTop + winSize.height;
if (fm.options.dialogContained || nodeFull) {
minTop = 0;
minLeft = 0;
} else {
minTop = nodeOffset.top * -1 + winSize.scrTop;
minLeft = nodeOffset.left * -1 + winSize.scrLeft;
}
css = {
top : outerSize.height >= winSize.height? minTop : Math.max(minTop, parseInt((elfNode.height() - outerSize.height)/2 - 42)),
left : outerSize.width >= winSize.width ? minLeft : Math.max(minLeft, parseInt((elfNode.width() - outerSize.width)/2))
};
if (outerSize.right + css.left > winSize.right) {
css.left = Math.max(minLeft, winSize.right - outerSize.right);
}
if (outerSize.bottom + css.top > winSize.bottom) {
css.top = Math.max(minTop, winSize.bottom - outerSize.bottom);
}
}
if (opts.absolute) {
css.position = 'absolute';
}
css && dialog.css(css);
})
.on('resize', function(e, data) {
var oh = 0, init = data && data.init, h, minH;
if ((data && (data.minimize || data.maxmize)) || dialog.data('minimized')) {
return;
}
e.stopPropagation();
e.preventDefault();
dialog.children('.ui-widget-header,.ui-dialog-buttonpane').each(function() {
oh += $(this).outerHeight(true);
});
if (!init && syncSize.enabled && !e.originalEvent && !dialog.hasClass('elfinder-maximized')) {
h = Math.min(syncSize.defaultSize.height, Math.max(parseInt(dialog.css('max-height')), parseInt(dialog.css('min-height'))) - oh - dialog.data('margin-y'));
} else {
h = dialog.height() - oh - dialog.data('margin-y');
}
self.height(h);
if (init) {
return;
}
posCheck();
minH = self.height();
minH = (h < minH)? (minH + oh + dialog.data('margin-y')) : opts.minHeight;
dialog.css('min-height', minH);
dialog.data('hasResizable') && dialog.resizable('option', { minHeight: minH });
if (typeof(opts.resize) === 'function') {
$.proxy(opts.resize, self[0])(e, data);
}
})
.on('tabstopsInit', tabstopsInit)
.on('focus', '.'+cltabstop, function() {
$(this).addClass(clhover).parent('label').addClass(clhover);
this.id && $(this).parent().find('label[for='+this.id+']').addClass(clhover);
})
.on('click', 'select.'+cltabstop, function() {
var node = $(this);
node.data('keepFocus')? node.removeData('keepFocus') : node.data('keepFocus', true);
})
.on('blur', '.'+cltabstop, function() {
$(this).removeClass(clhover).removeData('keepFocus').parent('label').removeClass(clhover);
this.id && $(this).parent().find('label[for='+this.id+']').removeClass(clhover);
})
.on('mouseenter mouseleave', '.'+cltabstop+',label', function(e) {
var $this = $(this), labelfor;
if (this.nodeName === 'LABEL') {
if (!$this.children('.'+cltabstop).length && (!(labelfor = $this.attr('for')) || !$('#'+labelfor).hasClass(cltabstop))) {
return;
}
}
if (opts.btnHoverFocus && dialog.data('focusOnMouseOver')) {
if (e.type === 'mouseenter' && ! $(':focus').data('keepFocus')) {
$this.trigger('focus');
}
} else {
$this.toggleClass(clhover, e.type == 'mouseenter');
}
})
.on('keydown', '.'+cltabstop, function(e) {
var $this = $(this),
esc, move, moveTo;
if ($this.is(':focus')) {
esc = e.keyCode === $.ui.keyCode.ESCAPE;
if (e.keyCode === $.ui.keyCode.ENTER) {
e.preventDefault();
$this.trigger('click');
} else if (((e.keyCode === $.ui.keyCode.TAB) && e.shiftKey) || e.keyCode === $.ui.keyCode.LEFT || e.keyCode == $.ui.keyCode.UP) {
move = 'prev';
} else if (e.keyCode === $.ui.keyCode.TAB || e.keyCode == $.ui.keyCode.RIGHT || e.keyCode == $.ui.keyCode.DOWN) {
move = 'next';
}
if (move
&&
(
($this.is('textarea') && !(e.ctrlKey || e.metaKey))
||
($this.is('select,span.ui-slider-handle') && e.keyCode !== $.ui.keyCode.TAB)
||
($this.is('input:not(:checkbox,:radio)') && (!(e.ctrlKey || e.metaKey) && e.keyCode === $.ui.keyCode[move === 'prev'? 'LEFT':'RIGHT']))
)
) {
e.stopPropagation();
return;
}
if (!esc) {
e.stopPropagation();
} else if ($this.is('input:not(:checkbox,:radio),textarea')) {
if ($this.val() !== '') {
$this.val('');
e.stopPropagation();
}
}
if (move) {
e.preventDefault();
(move === 'prev'? tabstopPrev : tabstopNext)(this).trigger('focus');
}
}
})
.data({modal: opts.modal}),
posCheck = function() {
var node = fm.getUI(),
pos;
if (node.hasClass('elfinder-fullscreen')) {
pos = dialog.position();
dialog.css('top', Math.max(Math.min(Math.max(pos.top, 0), node.height() - 100), 0));
dialog.css('left', Math.max(Math.min(Math.max(pos.left, 0), node.width() - 200), 0));
}
},
maxSize, toFocusNode;
dialog.prepend(titlebar);
makeHeaderBtn();
$.each(opts.buttons, function(name, cb) {
var button = $('<button type="button" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only '
+'elfinder-btncnt-'+(btnCnt++)+' '
+cltabstop
+'"><span class="ui-button-text">'+name+'</span></button>')
.on('click', $.proxy(cb, self[0]));
if (cb._cssClass) {
button.addClass(cb._cssClass);
}
if (platformWin) {
buttonset.append(button);
} else {
buttonset.prepend(button);
}
});
if (buttonset.children().length) {
dialog.append(buttonpane);
dialog.show();
buttonpane.find('button').each(function(i, btn) {
btnWidth += $(btn).outerWidth(true);
});
dialog.hide();
btnWidth += 20;
if (dialog.width() < btnWidth) {
dialog.width(btnWidth);
}
}
dialog.append(evCover);
if (syncSize.enabled) {
delta.width = dialog.outerWidth(true) - dialog.width() + ((dialog.outerWidth() - dialog.width()) / 2);
delta.height = dialog.outerHeight(true) - dialog.height() + ((dialog.outerHeight() - dialog.height()) / 2);
}
if (fm.options.dialogContained) {
maxSize = {
maxWidth: elfNode.width() - delta.width,
maxHeight: elfNode.height() - delta.height
};
opts.maxWidth = opts.maxWidth? Math.min(maxSize.maxWidth, opts.maxWidth) : maxSize.maxWidth;
opts.maxHeight = opts.maxHeight? Math.min(maxSize.maxHeight, opts.maxHeight) : maxSize.maxHeight;
dialog.css(maxSize);
}
restoreStyle = {
maxWidth : dialog.css('max-width'),
maxHeight : dialog.css('max-height'),
overflow : dialog.css('overflow')
};
if (opts.resizable) {
dialog.resizable({
minWidth : opts.minWidth,
minHeight : opts.minHeight,
maxWidth : opts.maxWidth,
maxHeight : opts.maxHeight,
start : function() {
evCover.show();
if (dialog.data('resizing') !== true && dialog.data('resizing')) {
clearTimeout(dialog.data('resizing'));
}
dialog.data('resizing', true);
},
stop : function(e, ui) {
evCover.hide();
dialog.data('resizing', setTimeout(function() {
dialog.data('resizing', false);
}, 200));
if (syncSize.enabled) {
syncSize.defaultSize = { width: self.width(), height: self.height() };
}
}
}).data('hasResizable', true);
}
numberToTel();
tabstopsInit();
typeof(opts.create) == 'function' && $.proxy(opts.create, this)();
if (opts.autoOpen) {
if (opts.open) {
requestAnimationFrame(function() {
self.elfinderdialog('open');
});
} else {
self.elfinderdialog('open');
}
}
if (opts.resize) {
fm.bind('themechange', function() {
setTimeout(function() {
dialog.data('margin-y', self.outerHeight(true) - self.height());
dialog.trigger('resize', {init: true});
}, 300);
});
}
});
return this;
};
$.fn.elfinderdialog.defaults = {
cssClass : '',
title : '',
modal : false,
resizable : true,
autoOpen : true,
closeOnEscape : true,
destroyOnClose : false,
buttons : {},
btnHoverFocus : true,
position : null,
absolute : false,
width : 320,
height : 'auto',
minWidth : 200,
minHeight : 70,
maxWidth : null,
maxHeight : null,
allowMinimize : 'auto',
allowMaximize : false,
openMaximized : false,
headerBtnPos : 'auto',
headerBtnOrder : 'auto',
optimizeNumber : true,
propagationEvents : ['mousemove', 'mouseup']
};
/*
* File: /js/ui/fullscreenbutton.js
*/
/**
* @class elFinder toolbar button to switch full scrren mode.
*
* @author Naoki Sawada
**/
$.fn.elfinderfullscreenbutton = function(cmd) {
return this.each(function() {
var button = $(this).elfinderbutton(cmd),
icon = button.children('.elfinder-button-icon'),
tm;
cmd.change(function() {
tm && cancelAnimationFrame(tm);
tm = requestAnimationFrame(function() {
var fullscreen = cmd.value;
icon.addClass('elfinder-button-icon-fullscreen').toggleClass('elfinder-button-icon-unfullscreen', fullscreen);
cmd.className = fullscreen? 'unfullscreen' : '';
});
});
});
};
/*
* File: /js/ui/navbar.js
*/
/**
* @class elfindernav - elFinder container for diretories tree and places
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfindernavbar = function(fm, opts) {
this.not('.elfinder-navbar').each(function() {
var nav = $(this).hide().addClass('ui-state-default elfinder-navbar'),
parent = nav.css('overflow', 'hidden').parent(),
wz = parent.children('.elfinder-workzone').append(nav),
ltr = fm.direction == 'ltr',
delta, deltaW, handle, swipeHandle, autoHide, setWidth, navdock,
setWzRect = function() {
var cwd = fm.getUI('cwd'),
wz = fm.getUI('workzone'),
wzRect = wz.data('rectangle'),
cwdOffset = cwd.offset();
wz.data('rectangle', Object.assign(wzRect, { cwdEdge: (fm.direction === 'ltr')? cwdOffset.left : cwdOffset.left + cwd.width() }));
},
setDelta = function() {
nav.css('overflow', 'hidden');
delta = Math.round(nav.outerHeight() - nav.height());
deltaW = Math.round(navdock.outerWidth() - navdock.innerWidth());
nav.css('overflow', 'auto');
};
fm.one('init', function() {
var set = function() {
navdock =fm.getUI('navdock');
setDelta();
fm.trigger('wzresize');
};
fm.bind('wzresize', function() {
var navdockH = 0;
navdock.width(nav.outerWidth() - deltaW);
if (navdock.children().length > 1) {
navdockH = navdock.outerHeight(true);
}
nav.height(wz.height() - navdockH - delta);
});
if (fm.cssloaded) {
set();
} else {
fm.one('cssloaded', set);
}
})
.one('opendone',function() {
handle && handle.trigger('resize');
nav.css('overflow', 'auto');
}).bind('themechange', setDelta);
if (fm.UA.Touch) {
autoHide = fm.storage('autoHide') || {};
if (typeof autoHide.navbar === 'undefined') {
autoHide.navbar = (opts.autoHideUA && opts.autoHideUA.length > 0 && $.grep(opts.autoHideUA, function(v){ return fm.UA[v]? true : false; }).length);
fm.storage('autoHide', autoHide);
}
if (autoHide.navbar) {
fm.one('init', function() {
if (nav.children().length) {
fm.uiAutoHide.push(function(){ nav.stop(true, true).trigger('navhide', { duration: 'slow', init: true }); });
}
});
}
fm.bind('load', function() {
if (nav.children().length) {
swipeHandle = $('<div class="elfinder-navbar-swipe-handle"/>').hide().appendTo(wz);
if (swipeHandle.css('pointer-events') !== 'none') {
swipeHandle.remove();
swipeHandle = null;
}
}
});
nav.on('navshow navhide', function(e, data) {
var mode = (e.type === 'navshow')? 'show' : 'hide',
duration = (data && data.duration)? data.duration : 'fast',
handleW = (data && data.handleW)? data.handleW : Math.max(50, fm.getUI().width() / 10);
nav.stop(true, true)[mode]({
duration: duration,
step : function() {
fm.trigger('wzresize');
},
complete: function() {
if (swipeHandle) {
if (mode === 'show') {
swipeHandle.stop(true, true).hide();
} else {
swipeHandle.width(handleW? handleW : '');
fm.resources.blink(swipeHandle, 'slowonce');
}
}
fm.trigger('navbar'+ mode);
data.init && fm.trigger('uiautohide');
setWzRect();
}
});
autoHide.navbar = (mode !== 'show');
fm.storage('autoHide', Object.assign(fm.storage('autoHide'), {navbar: autoHide.navbar}));
}).on('touchstart', function(e) {
if ($(this)['scroll' + (fm.direction === 'ltr'? 'Right' : 'Left')]() > 5) {
e.originalEvent._preventSwipeX = true;
}
});
}
if (! fm.UA.Mobile) {
handle = nav.resizable({
handles : ltr ? 'e' : 'w',
minWidth : opts.minWidth || 150,
maxWidth : opts.maxWidth || 500,
resize : function() {
fm.trigger('wzresize');
},
stop : function(e, ui) {
fm.storage('navbarWidth', ui.size.width);
setWzRect();
}
})
.on('resize scroll', function(e) {
var $this = $(this),
tm = $this.data('posinit');
e.preventDefault();
e.stopPropagation();
if (! ltr && e.type === 'resize') {
nav.css('left', 0);
}
tm && cancelAnimationFrame(tm);
$this.data('posinit', requestAnimationFrame(function() {
var offset = (fm.UA.Opera && nav.scrollLeft())? 20 : 2;
handle.css('top', 0).css({
top : parseInt(nav.scrollTop())+'px',
left : ltr ? 'auto' : parseInt(nav.scrollRight() - offset) * -1,
right: ltr ? parseInt(nav.scrollLeft() - offset) * -1 : 'auto'
});
if (e.type === 'resize') {
fm.getUI('cwd').trigger('resize');
}
}));
})
.children('.ui-resizable-handle').addClass('ui-front');
}
if (setWidth = fm.storage('navbarWidth')) {
nav.width(setWidth);
} else {
if (fm.UA.Mobile) {
fm.one('cssloaded', function() {
var set = function() {
setWidth = nav.parent().width() / 2;
if (nav.data('defWidth') > setWidth) {
nav.width(setWidth);
} else {
nav.width(nav.data('defWidth'));
}
nav.data('width', nav.width());
fm.trigger('wzresize');
};
nav.data('defWidth', nav.width());
$(window).on('resize.' + fm.namespace, set);
set();
});
}
}
});
return this;
};
/*
* File: /js/ui/navdock.js
*/
/**
* @class elfindernavdock - elFinder container for preview etc at below the navbar
*
* @author Naoki Sawada
**/
$.fn.elfindernavdock = function(fm, opts) {
this.not('.elfinder-navdock').each(function() {
var self = $(this).hide().addClass('ui-state-default elfinder-navdock touch-punch'),
node = self.parent(),
wz = node.children('.elfinder-workzone').append(self),
resize = function(to, h) {
var curH = h || self.height(),
diff = to - curH,
len = Object.keys(sizeSyncs).length,
calc = len? diff / len : 0,
ovf;
if (diff) {
ovf = self.css('overflow');
self.css('overflow', 'hidden');
self.height(to);
$.each(sizeSyncs, function(id, n) {
n.height(n.height() + calc).trigger('resize.' + fm.namespace);
});
fm.trigger('wzresize');
self.css('overflow', ovf);
}
},
handle = $('<div class="ui-front ui-resizable-handle ui-resizable-n"/>').appendTo(self),
sizeSyncs = {},
resizeFn = [],
initMaxHeight = (parseInt(opts.initMaxHeight) || 50) / 100,
maxHeight = (parseInt(opts.maxHeight) || 90) / 100,
basicHeight, hasNode;
self.data('addNode', function(cNode, opts) {
var wzH = fm.getUI('workzone').height(),
imaxH = wzH * initMaxHeight,
curH, tH, mH;
opts = Object.assign({
first: false,
sizeSync: true,
init: false
}, opts);
if (!cNode.attr('id')) {
cNode.attr('id', fm.namespace+'-navdock-' + (+new Date()));
}
opts.sizeSync && (sizeSyncs[cNode.attr('id')] = cNode);
curH = self.height();
tH = curH + cNode.outerHeight(true);
if (opts.first) {
handle.after(cNode);
} else {
self.append(cNode);
}
hasNode = true;
self.resizable('enable').height(tH).show();
fm.trigger('wzresize');
if (opts.init) {
mH = fm.storage('navdockHeight');
if (mH) {
tH = mH;
} else {
tH = tH > imaxH? imaxH : tH;
}
basicHeight = tH;
}
resize(Math.min(tH, wzH * maxHeight));
return self;
}).data('removeNode', function(nodeId, appendTo) {
var cNode = $('#'+nodeId);
delete sizeSyncs[nodeId];
self.height(self.height() - $('#'+nodeId).outerHeight(true));
if (appendTo) {
if (appendTo === 'detach') {
cNode = cNode.detach();
} else {
appendTo.append(cNode);
}
} else {
cNode.remove();
}
if (self.children().length <= 1) {
hasNode = false;
self.resizable('disable').height(0).hide();
}
fm.trigger('wzresize');
return cNode;
});
if (! opts.disabled) {
fm.one('init', function() {
var ovf;
if (fm.getUI('navbar').children().not('.ui-resizable-handle').length) {
self.data('dockEnabled', true);
self.resizable({
maxHeight: fm.getUI('workzone').height() * maxHeight,
handles: { n: handle },
start: function(e, ui) {
ovf = self.css('overflow');
self.css('overflow', 'hidden');
fm.trigger('navdockresizestart', {event: e, ui: ui}, true);
},
resize: function(e, ui) {
self.css('top', '');
fm.trigger('wzresize', { inNavdockResize : true });
},
stop: function(e, ui) {
fm.trigger('navdockresizestop', {event: e, ui: ui}, true);
self.css('top', '');
basicHeight = ui.size.height;
fm.storage('navdockHeight', basicHeight);
resize(basicHeight, ui.originalSize.height);
self.css('overflow', ovf);
}
});
fm.bind('wzresize', function(e) {
var minH, maxH, h;
if (self.is(':visible')) {
maxH = fm.getUI('workzone').height() * maxHeight;
if (! e.data || ! e.data.inNavdockResize) {
h = self.height();
if (maxH < basicHeight) {
if (Math.abs(h - maxH) > 1) {
resize(maxH);
}
} else {
if (Math.abs(h - basicHeight) > 1) {
resize(basicHeight);
}
}
}
self.resizable('option', 'maxHeight', maxH);
}
}).bind('themechange', function() {
var oldH = Math.round(self.height());
requestAnimationFrame(function() {
var curH = Math.round(self.height()),
diff = oldH - curH;
if (diff !== 0) {
resize(self.height(), curH - diff);
}
});
});
}
fm.bind('navbarshow navbarhide', function(e) {
self[hasNode && e.type === 'navbarshow'? 'show' : 'hide']();
});
});
}
});
return this;
};
/*
* File: /js/ui/overlay.js
*/
$.fn.elfinderoverlay = function(opts) {
var fm = this.parent().elfinder('instance'),
o, cnt, show, hide;
this.filter(':not(.elfinder-overlay)').each(function() {
opts = Object.assign({}, opts);
$(this).addClass('ui-front ui-widget-overlay elfinder-overlay')
.hide()
.on('mousedown', function(e) {
e.preventDefault();
e.stopPropagation();
})
.data({
cnt : 0,
show : typeof(opts.show) == 'function' ? opts.show : function() { },
hide : typeof(opts.hide) == 'function' ? opts.hide : function() { }
});
});
if (opts == 'show') {
o = this.eq(0);
cnt = o.data('cnt') + 1;
show = o.data('show');
fm.toFront(o);
o.data('cnt', cnt);
if (o.is(':hidden')) {
o.show();
show();
}
}
if (opts == 'hide') {
o = this.eq(0);
cnt = o.data('cnt') - 1;
hide = o.data('hide');
o.data('cnt', cnt);
if (cnt <= 0) {
o.hide();
hide();
}
}
return this;
};
/*
* File: /js/ui/panel.js
*/
$.fn.elfinderpanel = function(fm) {
return this.each(function() {
var panel = $(this).addClass('elfinder-panel ui-state-default ui-corner-all'),
margin = 'margin-'+(fm.direction == 'ltr' ? 'left' : 'right');
fm.one('load', function(e) {
var navbar = fm.getUI('navbar');
panel.css(margin, parseInt(navbar.outerWidth(true)));
navbar.on('resize', function(e) {
e.preventDefault();
e.stopPropagation();
panel.is(':visible') && panel.css(margin, parseInt(navbar.outerWidth(true)));
});
});
});
};
/*
* File: /js/ui/path.js
*/
/**
* @class elFinder ui
* Display current folder path in statusbar.
* Click on folder name in path - open folder
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfinderpath = function(fm, options) {
return this.each(function() {
var query = '',
target = '',
mimes = [],
place = 'statusbar',
clHover= fm.res('class', 'hover'),
prefix = 'path' + (elFinder.prototype.uniqueid? elFinder.prototype.uniqueid : '') + '-',
wzbase = $('<div class="ui-widget-header ui-helper-clearfix elfinder-workzone-path"/>'),
path = $(this).addClass('elfinder-path').html('&nbsp;')
.on('mousedown', 'span.elfinder-path-dir', function(e) {
var hash = $(this).attr('id').substr(prefix.length);
e.preventDefault();
if (hash != fm.cwd().hash) {
$(this).addClass(clHover);
if (query) {
fm.exec('search', query, { target: hash, mime: mimes.join(' ') });
} else {
fm.trigger('select', {selected : [hash]}).exec('open', hash);
}
}
})
.prependTo(fm.getUI('statusbar').show()),
roots = $('<div class="elfinder-path-roots"/>').on('click', function(e) {
e.stopPropagation();
e.preventDefault();
var roots = $.map(fm.roots, function(h) { return fm.file(h); }),
raw = [];
$.each(roots, function(i, f) {
if (! f.phash && fm.root(fm.cwd().hash, true) !== f.hash) {
raw.push({
label : fm.escape(f.i18 || f.name),
icon : 'home',
callback : function() { fm.exec('open', f.hash); },
options : {
iconClass : f.csscls || '',
iconImg : f.icon || ''
}
});
}
});
fm.trigger('contextmenu', {
raw: raw,
x: e.pageX,
y: e.pageY
});
}).append('<span class="elfinder-button-icon elfinder-button-icon-menu" />').appendTo(wzbase),
render = function(cwd) {
var dirs = [],
names = [];
$.each(fm.parents(cwd), function(i, hash) {
var c = (cwd === hash)? 'elfinder-path-dir elfinder-path-cwd' : 'elfinder-path-dir',
f = fm.file(hash),
name = fm.escape(f.i18 || f.name);
names.push(name);
dirs.push('<span id="'+prefix+hash+'" class="'+c+'" title="'+names.join(fm.option('separator'))+'">'+name+'</span>');
});
return dirs.join('<span class="elfinder-path-other">'+fm.option('separator')+'</span>');
},
toWorkzone = function() {
var prev;
path.children('span.elfinder-path-dir').attr('style', '');
prev = fm.direction === 'ltr'? $('#'+prefix + fm.cwd().hash).prevAll('span.elfinder-path-dir:first') : $();
path.scrollLeft(prev.length? prev.position().left : 0);
},
fit = function() {
if (fm.UA.CSS.flex) {
return;
}
var dirs = path.children('span.elfinder-path-dir'),
cnt = dirs.length,
m, bg = 0, ids;
if (place === 'workzone' || cnt < 2) {
dirs.attr('style', '');
return;
}
path.width(path.css('max-width'));
dirs.css({maxWidth: (100/cnt)+'%', display: 'inline-block'});
m = path.width() - 9;
path.children('span.elfinder-path-other').each(function() {
m -= $(this).width();
});
ids = [];
dirs.each(function(i) {
var dir = $(this),
w = dir.width();
m -= w;
if (w < this.scrollWidth) {
ids.push(i);
}
});
path.width('');
if (ids.length) {
if (m > 0) {
m = m / ids.length;
$.each(ids, function(i, k) {
var d = $(dirs[k]);
d.css('max-width', d.width() + m);
});
}
dirs.last().attr('style', '');
} else {
dirs.attr('style', '');
}
},
hasUiTree, hasUiStat;
fm.one('init', function() {
hasUiTree = fm.getUI('tree').length;
hasUiStat = fm.getUI('stat').length;
if (! hasUiTree && options.toWorkzoneWithoutNavbar) {
wzbase.append(path).insertBefore(fm.getUI('workzone'));
place = 'workzone';
fm.bind('open', toWorkzone)
.one('opendone', function() {
fm.getUI().trigger('resize');
});
}
})
.bind('open searchend parents', function() {
var dirs = [];
query = '';
target = '';
mimes = [];
path.html(render(fm.cwd().hash));
if (Object.keys(fm.roots).length > 1) {
path.css('margin', '');
roots.show();
} else {
path.css('margin', 0);
roots.hide();
}
!hasUiStat && fit();
})
.bind('searchstart', function(e) {
if (e.data) {
query = e.data.query || '';
target = e.data.target || '';
mimes = e.data.mimes || [];
}
})
.bind('search', function(e) {
var dirs = [],
html = '';
if (target) {
html = render(target);
} else {
html = fm.i18n('btnAll');
}
path.html('<span class="elfinder-path-other">'+fm.i18n('searcresult') + ': </span>' + html);
fit();
})
// on swipe to navbar show/hide
.bind('navbarshow navbarhide', function() {
var wz = fm.getUI('workzone');
if (this.type === 'navbarshow') {
fm.unbind('open', toWorkzone);
path.prependTo(fm.getUI('statusbar'));
wzbase.detach();
place = 'statusbar';
} else {
wzbase.append(path).insertBefore(wz);
place = 'workzone';
toWorkzone();
fm.bind('open', toWorkzone);
}
fm.trigger('uiresize');
})
.bind('resize uistatchange', fit);
});
};
/*
* File: /js/ui/places.js
*/
/**
* @class elFinder places/favorites ui
*
* @author Dmitry (dio) Levashov
* @author Naoki Sawada
**/
$.fn.elfinderplaces = function(fm, opts) {
return this.each(function() {
var dirs = {},
c = 'class',
navdir = fm.res(c, 'navdir'),
collapsed = fm.res(c, 'navcollapse'),
expanded = fm.res(c, 'navexpand'),
hover = fm.res(c, 'hover'),
clroot = fm.res(c, 'treeroot'),
dropover = fm.res(c, 'adroppable'),
tpl = fm.res('tpl', 'placedir'),
ptpl = fm.res('tpl', 'perms'),
spinner = $(fm.res('tpl', 'navspinner')),
suffix = opts.suffix? opts.suffix : '',
key = 'places' + suffix,
menuTimer = null,
/**
* Convert places dir node into dir hash
*
* @param String directory id
* @return String
**/
id2hash = function(id) { return id.substr(6); },
/**
* Convert places dir node into dir hash
*
* @param String directory id
* @return String
**/
hash2id = function(hash) { return 'place-'+hash; },
/**
* Save current places state
*
* @return void
**/
save = function() {
var hashes = [], data = {};
hashes = $.map(subtree.children().find('[id]'), function(n) {
return id2hash(n.id);
});
if (hashes.length) {
$.each(hashes.reverse(), function(i, h) {
data[h] = dirs[h];
});
} else {
data = null;
}
fm.storage(key, data);
},
/**
* Init dir at places
*
* @return void
**/
init = function() {
var dat, hashes;
key = 'places'+(opts.suffix? opts.suffix : ''),
dirs = {};
dat = fm.storage(key);
if (typeof dat === 'string') {
// old data type elFinder <= 2.1.12
dat = $.grep(dat.split(','), function(hash) { return hash? true : false;});
$.each(dat, function(i, d) {
var dir = d.split('#');
dirs[dir[0]] = dir[1]? dir[1] : dir[0];
});
} else if ($.isPlainObject(dat)) {
dirs = dat;
}
// allow modify `dirs`
/**
* example for preset places
*
* elfinderInstance.bind('placesload', function(e, fm) {
* //if (fm.storage(e.data.storageKey) === null) { // for first time only
* if (!fm.storage(e.data.storageKey)) { // for empty places
* e.data.dirs[targetHash] = fallbackName; // preset folder
* }
* }
**/
fm.trigger('placesload', {dirs: dirs, storageKey: key}, true);
hashes = Object.keys(dirs);
if (hashes.length) {
root.prepend(spinner);
fm.request({
data : {cmd : 'info', targets : hashes},
preventDefault : true
})
.done(function(data) {
var exists = {};
data.files && data.files.length && fm.cache(data.files);
$.each(data.files, function(i, f) {
var hash = f.hash;
exists[hash] = f;
});
$.each(dirs, function(h, f) {
add(exists[h] || Object.assign({notfound: true}, f));
});
if (fm.storage('placesState') > 0) {
root.trigger('click');
}
})
.always(function() {
spinner.remove();
});
}
},
/**
* Return node for given dir object
*
* @param Object directory object
* @return jQuery
**/
create = function(dir, hash) {
return $(tpl.replace(/\{id\}/, hash2id(dir? dir.hash : hash))
.replace(/\{name\}/, fm.escape(dir? dir.i18 || dir.name : hash))
.replace(/\{cssclass\}/, dir? (fm.perms2class(dir) + (dir.notfound? ' elfinder-na' : '') + (dir.csscls? ' '+dir.csscls : '')) : '')
.replace(/\{permissions\}/, (dir && (!dir.read || !dir.write || dir.notfound))? ptpl : '')
.replace(/\{title\}/, (dir && dir.path)? fm.escape(dir.path) : '')
.replace(/\{symlink\}/, '')
.replace(/\{style\}/, (dir && dir.icon)? fm.getIconStyle(dir) : ''));
},
/**
* Add new node into places
*
* @param Object directory object
* @return void
**/
add = function(dir) {
var node, hash;
if (dir.mime !== 'directory') {
return false;
}
hash = dir.hash;
if (!fm.files().hasOwnProperty(hash)) {
// update cache
fm.trigger('tree', {tree: [dir]});
}
node = create(dir, hash);
dirs[hash] = dir;
subtree.prepend(node);
root.addClass(collapsed);
sortBtn.toggle(subtree.children().length > 1);
return true;
},
/**
* Remove dir from places
*
* @param String directory hash
* @return String removed name
**/
remove = function(hash) {
var name = null, tgt, cnt;
if (dirs[hash]) {
delete dirs[hash];
tgt = $('#'+hash2id(hash));
if (tgt.length) {
name = tgt.text();
tgt.parent().remove();
cnt = subtree.children().length;
sortBtn.toggle(cnt > 1);
if (! cnt) {
root.removeClass(collapsed);
places.removeClass(expanded);
subtree.slideToggle(false);
}
}
}
return name;
},
/**
* Move up dir on places
*
* @param String directory hash
* @return void
**/
moveup = function(hash) {
var self = $('#'+hash2id(hash)),
tgt = self.parent(),
prev = tgt.prev('div'),
cls = 'ui-state-hover',
ctm = fm.getUI('contextmenu');
menuTimer && clearTimeout(menuTimer);
if (prev.length) {
ctm.find(':first').data('placesHash', hash);
self.addClass(cls);
tgt.insertBefore(prev);
prev = tgt.prev('div');
menuTimer = setTimeout(function() {
self.removeClass(cls);
if (ctm.find(':first').data('placesHash') === hash) {
ctm.hide().empty();
}
}, 1500);
}
if(!prev.length) {
self.removeClass(cls);
ctm.hide().empty();
}
},
/**
* Update dir at places
*
* @param Object directory
* @param String previous hash
* @return Boolean
**/
update = function(dir, preHash) {
var hash = dir.hash,
tgt = $('#'+hash2id(preHash || hash)),
node = create(dir, hash);
if (tgt.length > 0) {
tgt.parent().replaceWith(node);
dirs[hash] = dir;
return true;
} else {
return false;
}
},
/**
* Remove all dir from places
*
* @return void
**/
clear = function() {
subtree.empty();
root.removeClass(collapsed);
places.removeClass(expanded);
subtree.slideToggle(false);
},
/**
* Sort places dirs A-Z
*
* @return void
**/
sort = function() {
$.each(dirs, function(h, f) {
var dir = fm.file(h) || f,
node = create(dir, h),
ret = null;
if (!dir) {
node.hide();
}
if (subtree.children().length) {
$.each(subtree.children(), function() {
var current = $(this);
if ((dir.i18 || dir.name).localeCompare(current.children('.'+navdir).text()) < 0) {
ret = !node.insertBefore(current);
return ret;
}
});
if (ret !== null) {
return true;
}
}
!$('#'+hash2id(h)).length && subtree.append(node);
});
save();
},
// sort button
sortBtn = $('<span class="elfinder-button-icon elfinder-button-icon-sort elfinder-places-root-icon" title="'+fm.i18n('cmdsort')+'"/>')
.hide()
.on('click', function(e) {
e.stopPropagation();
subtree.empty();
sort();
}
),
/**
* Node - wrapper for places root
*
* @type jQuery
**/
wrapper = create({
hash : 'root-'+fm.namespace,
name : fm.i18n(opts.name, 'places'),
read : true,
write : true
}),
/**
* Places root node
*
* @type jQuery
**/
root = wrapper.children('.'+navdir)
.addClass(clroot)
.on('click', function(e) {
e.stopPropagation();
if (root.hasClass(collapsed)) {
places.toggleClass(expanded);
subtree.slideToggle();
fm.storage('placesState', places.hasClass(expanded)? 1 : 0);
}
})
.append(sortBtn),
/**
* Container for dirs
*
* @type jQuery
**/
subtree = wrapper.children('.'+fm.res(c, 'navsubtree')),
/**
* Main places container
*
* @type jQuery
**/
places = $(this).addClass(fm.res(c, 'tree')+' elfinder-places ui-corner-all')
.hide()
.append(wrapper)
.appendTo(fm.getUI('navbar'))
.on('mouseenter mouseleave', '.'+navdir, function(e) {
$(this).toggleClass('ui-state-hover', (e.type == 'mouseenter'));
})
.on('click', '.'+navdir, function(e) {
var p = $(this);
if (p.data('longtap')) {
e.stopPropagation();
return;
}
! p.hasClass('elfinder-na') && fm.exec('open', p.attr('id').substr(6));
})
.on('contextmenu', '.'+navdir+':not(.'+clroot+')', function(e) {
var self = $(this),
hash = self.attr('id').substr(6);
e.preventDefault();
fm.trigger('contextmenu', {
raw : [{
label : fm.i18n('moveUp'),
icon : 'up',
remain : true,
callback : function() { moveup(hash); save(); }
},'|',{
label : fm.i18n('rmFromPlaces'),
icon : 'rm',
callback : function() { remove(hash); save(); }
}],
'x' : e.pageX,
'y' : e.pageY
});
self.addClass('ui-state-hover');
fm.getUI('contextmenu').children().on('mouseenter', function() {
self.addClass('ui-state-hover');
});
fm.bind('closecontextmenu', function() {
self.removeClass('ui-state-hover');
});
})
.droppable({
tolerance : 'pointer',
accept : '.elfinder-cwd-file-wrapper,.elfinder-tree-dir,.elfinder-cwd-file',
hoverClass : fm.res('class', 'adroppable'),
classes : { // Deprecated hoverClass jQueryUI>=1.12.0
'ui-droppable-hover': fm.res('class', 'adroppable')
},
over : function(e, ui) {
var helper = ui.helper,
dir = $.grep(helper.data('files'), function(h) { return (fm.file(h).mime === 'directory' && !dirs[h])? true : false; });
e.stopPropagation();
helper.data('dropover', helper.data('dropover') + 1);
if (fm.insideWorkzone(e.pageX, e.pageY)) {
if (dir.length > 0) {
helper.addClass('elfinder-drag-helper-plus');
fm.trigger('unlockfiles', {files : helper.data('files'), helper: helper});
} else {
$(this).removeClass(dropover);
}
}
},
out : function(e, ui) {
var helper = ui.helper;
e.stopPropagation();
helper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus').data('dropover', Math.max(helper.data('dropover') - 1, 0));
$(this).removeData('dropover')
.removeClass(dropover);
},
drop : function(e, ui) {
var helper = ui.helper,
resolve = true;
$.each(helper.data('files'), function(i, hash) {
var dir = fm.file(hash);
if (dir && dir.mime == 'directory' && !dirs[dir.hash]) {
add(dir);
} else {
resolve = false;
}
});
save();
resolve && helper.hide();
}
})
// for touch device
.on('touchstart', '.'+navdir+':not(.'+clroot+')', function(e) {
if (e.originalEvent.touches.length > 1) {
return;
}
var hash = $(this).attr('id').substr(6),
p = $(this)
.addClass(hover)
.data('longtap', null)
.data('tmlongtap', setTimeout(function(){
// long tap
p.data('longtap', true);
fm.trigger('contextmenu', {
raw : [{
label : fm.i18n('rmFromPlaces'),
icon : 'rm',
callback : function() { remove(hash); save(); }
}],
'x' : e.originalEvent.touches[0].pageX,
'y' : e.originalEvent.touches[0].pageY
});
}, 500));
})
.on('touchmove touchend', '.'+navdir+':not(.'+clroot+')', function(e) {
clearTimeout($(this).data('tmlongtap'));
if (e.type == 'touchmove') {
$(this).removeClass(hover);
}
});
if ($.fn.sortable) {
subtree.addClass('touch-punch')
.sortable({
appendTo : fm.getUI(),
revert : false,
helper : function(e) {
var dir = $(e.target).parent();
dir.children().removeClass('ui-state-hover');
return $('<div class="ui-widget elfinder-place-drag elfinder-'+fm.direction+'"/>')
.append($('<div class="elfinder-navbar"/>').show().append(dir.clone()));
},
stop : function(e, ui) {
var target = $(ui.item[0]),
top = places.offset().top,
left = places.offset().left,
width = places.width(),
height = places.height(),
x = e.pageX,
y = e.pageY;
if (!(x > left && x < left+width && y > top && y < y+height)) {
remove(id2hash(target.children(':first').attr('id')));
save();
}
},
update : function(e, ui) {
save();
}
});
}
// "on regist" for command exec
$(this).on('regist', function(e, files){
var added = false;
$.each(files, function(i, dir) {
if (dir && dir.mime == 'directory' && !dirs[dir.hash]) {
if (add(dir)) {
added = true;
}
}
});
added && save();
});
// on fm load - show places and load files from backend
fm.one('load', function() {
var dat, hashes;
if (fm.oldAPI) {
return;
}
places.show().parent().show();
init();
fm.change(function(e) {
var changed = false;
$.each(e.data.changed, function(i, file) {
if (dirs[file.hash]) {
if (file.mime !== 'directory') {
if (remove(file.hash)) {
changed = true;
}
} else {
if (update(file)) {
changed = true;
}
}
}
});
changed && save();
})
.bind('rename', function(e) {
var changed = false;
if (e.data.removed) {
$.each(e.data.removed, function(i, hash) {
if (e.data.added[i]) {
if (update(e.data.added[i], hash)) {
changed = true;
}
}
});
}
changed && save();
})
.bind('rm paste', function(e) {
var names = [],
changed = false;
if (e.data.removed) {
$.each(e.data.removed, function(i, hash) {
var name = remove(hash);
name && names.push(name);
});
}
if (names.length) {
changed = true;
}
if (e.data.added && names.length) {
$.each(e.data.added, function(i, file) {
if ($.inArray(file.name, names) !== 1) {
file.mime == 'directory' && add(file);
}
});
}
changed && save();
})
.bind('sync netmount', function() {
var ev = this,
opSuffix = opts.suffix? opts.suffix : '',
hashes;
if (ev.type === 'sync') {
// check is change of opts.suffix
if (suffix !== opSuffix) {
suffix = opSuffix;
clear();
init();
return;
}
}
hashes = Object.keys(dirs);
if (hashes.length) {
root.prepend(spinner);
fm.request({
data : {cmd : 'info', targets : hashes},
preventDefault : true
})
.done(function(data) {
var exists = {},
updated = false,
cwd = fm.cwd().hash;
$.each(data.files || [], function(i, file) {
var hash = file.hash;
exists[hash] = file;
if (!fm.files().hasOwnProperty(file.hash)) {
// update cache
fm.trigger('tree', {tree: [file]});
}
});
$.each(dirs, function(h, f) {
if (f.notfound === Boolean(exists[h])) {
if ((f.phash === cwd && ev.type !== 'netmount') || (exists[h] && exists[h].mime !== 'directory')) {
if (remove(h)) {
updated = true;
}
} else {
if (update(exists[h] || Object.assign({notfound: true}, f))) {
updated = true;
}
}
} else if (exists[h] && exists[h].phash != cwd) {
// update permission of except cwd
update(exists[h]);
}
});
updated && save();
})
.always(function() {
spinner.remove();
});
}
});
});
});
};
/*
* File: /js/ui/searchbutton.js
*/
/**
* @class elFinder toolbar search button widget.
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfindersearchbutton = function(cmd) {
return this.each(function() {
var result = false,
fm = cmd.fm,
isopts = cmd.options.incsearch || { enable: false },
sTypes = cmd.options.searchTypes,
id = function(name){return fm.namespace + fm.escape(name);},
toolbar= fm.getUI('toolbar'),
btnCls = fm.res('class', 'searchbtn'),
button = $(this)
.hide()
.addClass('ui-widget-content elfinder-button '+btnCls)
.on('click', function(e) {
e.stopPropagation();
}),
search = function() {
input.data('inctm') && clearTimeout(input.data('inctm'));
var val = $.trim(input.val()),
from = !$('#' + id('SearchFromAll')).prop('checked'),
mime = $('#' + id('SearchMime')).prop('checked'),
type = '';
if (from) {
if ($('#' + id('SearchFromVol')).prop('checked')) {
from = fm.root(fm.cwd().hash);
} else {
from = fm.cwd().hash;
}
}
if (mime) {
mime = val;
val = '.';
}
if (typeSet) {
type = typeSet.children('input:checked').val();
}
if (val) {
input.trigger('focus');
cmd.exec(val, from, mime, type).done(function() {
result = true;
}).fail(function() {
abort();
});
} else {
fm.trigger('searchend');
}
},
abort = function() {
input.data('inctm') && clearTimeout(input.data('inctm'));
input.val('').trigger('blur');
if (result || incVal) {
result = false;
incVal = '';
fm.lazy(function() {
fm.trigger('searchend');
});
}
},
incVal = '',
input = $('<input type="text" size="42"/>')
.on('focus', function() {
inFocus = true;
incVal = '';
button.addClass('ui-state-active');
fm.trigger('uiresize');
opts && opts.slideDown(function() {
// Care for on browser window re-active
button.addClass('ui-state-active');
fm.toFront(opts);
});
})
.on('blur', function() {
inFocus = false;
if (opts) {
if (!opts.data('infocus')) {
opts.slideUp(function() {
button.removeClass('ui-state-active');
fm.trigger('uiresize');
fm.toHide(opts);
});
} else {
opts.data('infocus', false);
}
} else {
button.removeClass('ui-state-active');
}
})
.appendTo(button)
// to avoid fm shortcuts on arrows
.on('keypress', function(e) {
e.stopPropagation();
})
.on('keydown', function(e) {
e.stopPropagation();
if (e.keyCode === $.ui.keyCode.ENTER) {
search();
} else if (e.keyCode === $.ui.keyCode.ESCAPE) {
e.preventDefault();
abort();
}
}),
opts, typeSet, cwdReady, inFocus;
if (isopts.enable) {
isopts.minlen = isopts.minlen || 2;
isopts.wait = isopts.wait || 500;
input
.attr('title', fm.i18n('incSearchOnly'))
.on('compositionstart', function() {
input.data('composing', true);
})
.on('compositionend', function() {
input.removeData('composing');
input.trigger('input'); // for IE, edge
})
.on('input', function() {
if (! input.data('composing')) {
input.data('inctm') && clearTimeout(input.data('inctm'));
input.data('inctm', setTimeout(function() {
var val = input.val();
if (val.length === 0 || val.length >= isopts.minlen) {
(incVal !== val) && fm.trigger('incsearchstart', { query: val });
incVal = val;
if (val === '' && fm.searchStatus.state > 1 && fm.searchStatus.query) {
input.val(fm.searchStatus.query).trigger('select');
}
}
}, isopts.wait));
}
});
if (fm.UA.ltIE8) {
input.on('keydown', function(e) {
if (e.keyCode === 229) {
input.data('imetm') && clearTimeout(input.data('imetm'));
input.data('composing', true);
input.data('imetm', setTimeout(function() {
input.removeData('composing');
}, 100));
}
})
.on('keyup', function(e) {
input.data('imetm') && clearTimeout(input.data('imetm'));
if (input.data('composing')) {
e.keyCode === $.ui.keyCode.ENTER && input.trigger('compositionend');
} else {
input.trigger('input');
}
});
}
}
$('<span class="ui-icon ui-icon-search" title="'+cmd.title+'"/>')
.appendTo(button)
.on('mousedown', function(e) {
e.stopPropagation();
e.preventDefault();
if (button.hasClass('ui-state-active')) {
search();
} else {
input.trigger('focus');
}
});
$('<span class="ui-icon ui-icon-close"/>')
.appendTo(button)
.on('mousedown', function(e) {
e.stopPropagation();
e.preventDefault();
if (input.val() === '' && !button.hasClass('ui-state-active')) {
input.trigger('focus');
} else {
abort();
}
});
// wait when button will be added to DOM
fm.bind('toolbarload', function(){
var parent = button.parent();
if (parent.length) {
toolbar.prepend(button.show());
parent.remove();
// position icons for ie7
if (fm.UA.ltIE7) {
var icon = button.children(fm.direction == 'ltr' ? '.ui-icon-close' : '.ui-icon-search');
icon.css({
right : '',
left : parseInt(button.width())-icon.outerWidth(true)
});
}
}
});
fm
.one('init', function() {
fm.getUI('cwd').on('touchstart click', function() {
inFocus && input.trigger('blur');
});
})
.one('open', function() {
opts = (fm.api < 2.1)? null : $('<div class="ui-front ui-widget ui-widget-content elfinder-button-search-menu ui-corner-all"/>')
.append(
$('<div class="buttonset"/>')
.append(
$('<input id="'+id('SearchFromCwd')+'" name="serchfrom" type="radio" checked="checked"/><label for="'+id('SearchFromCwd')+'">'+fm.i18n('btnCwd')+'</label>'),
$('<input id="'+id('SearchFromVol')+'" name="serchfrom" type="radio"/><label for="'+id('SearchFromVol')+'">'+fm.i18n('btnVolume')+'</label>'),
$('<input id="'+id('SearchFromAll')+'" name="serchfrom" type="radio"/><label for="'+id('SearchFromAll')+'">'+fm.i18n('btnAll')+'</label>')
),
$('<div class="buttonset elfinder-search-type"/>')
.append(
$('<input id="'+id('SearchName')+'" name="serchcol" type="radio" checked="checked" value="SearchName"/><label for="'+id('SearchName')+'">'+fm.i18n('btnFileName')+'</label>')
)
)
.hide()
.appendTo(fm.getUI());
if (opts) {
if (sTypes) {
typeSet = opts.find('.elfinder-search-type');
$.each(cmd.options.searchTypes, function(i, v) {
typeSet.append($('<input id="'+id(i)+'" name="serchcol" type="radio" value="'+fm.escape(i)+'"/><label for="'+id(i)+'">'+fm.i18n(v.name)+'</label>'));
});
}
opts.find('div.buttonset').buttonset();
$('#'+id('SearchFromAll')).next('label').attr('title', fm.i18n('searchTarget', fm.i18n('btnAll')));
if (sTypes) {
$.each(sTypes, function(i, v) {
if (v.title) {
$('#'+id(i)).next('label').attr('title', fm.i18n(v.title));
}
});
}
opts.on('mousedown', 'div.buttonset', function(e){
e.stopPropagation();
opts.data('infocus', true);
})
.on('click', 'input', function(e) {
e.stopPropagation();
$.trim(input.val())? search() : input.trigger('focus');
})
.on('close', function() {
input.trigger('blur');
});
}
})
.bind('searchend', function() {
input.val('');
})
.bind('open parents', function() {
var dirs = [],
volroot = fm.file(fm.root(fm.cwd().hash));
if (volroot) {
$.each(fm.parents(fm.cwd().hash), function(i, hash) {
dirs.push(fm.file(hash).name);
});
$('#'+id('SearchFromCwd')).next('label').attr('title', fm.i18n('searchTarget', dirs.join(fm.option('separator'))));
$('#'+id('SearchFromVol')).next('label').attr('title', fm.i18n('searchTarget', volroot.name));
}
})
.bind('open', function() {
incVal && abort();
})
.bind('cwdinit', function() {
cwdReady = false;
})
.bind('cwdrender',function() {
cwdReady = true;
})
.bind('keydownEsc', function() {
if (incVal && incVal.substr(0, 1) === '/') {
incVal = '';
input.val('');
fm.trigger('searchend');
}
})
.shortcut({
pattern : 'ctrl+f f3',
description : cmd.title,
callback : function() {
input.trigger('select').trigger('focus');
}
})
.shortcut({
pattern : 'a b c d e f g h i j k l m n o p q r s t u v w x y z dig0 dig1 dig2 dig3 dig4 dig5 dig6 dig7 dig8 dig9 num0 num1 num2 num3 num4 num5 num6 num7 num8 num9',
description : fm.i18n('firstLetterSearch'),
callback : function(e) {
if (! cwdReady) { return; }
var code = e.originalEvent.keyCode,
next = function() {
var sel = fm.selected(),
key = $.ui.keyCode[(!sel.length || $('#'+fm.cwdHash2Id(sel[0])).next('[id]').length)? 'RIGHT' : 'HOME'];
$(document).trigger($.Event('keydown', { keyCode: key, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false }));
},
val;
if (code >= 96 && code <= 105) {
code -= 48;
}
val = '/' + String.fromCharCode(code);
if (incVal !== val) {
input.val(val);
incVal = val;
fm
.trigger('incsearchstart', { query: val })
.one('cwdrender', next);
} else{
next();
}
}
});
});
};
/*
* File: /js/ui/sortbutton.js
*/
/**
* @class elFinder toolbar button menu with sort variants.
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfindersortbutton = function(cmd) {
return this.each(function() {
var fm = cmd.fm,
name = cmd.name,
c = 'class',
disabled = fm.res(c, 'disabled'),
hover = fm.res(c, 'hover'),
item = 'elfinder-button-menu-item',
selected = item+'-selected',
asc = selected+'-asc',
desc = selected+'-desc',
text = $('<span class="elfinder-button-text">'+cmd.title+'</span>'),
button = $(this).addClass('ui-state-default elfinder-button elfinder-menubutton elfiner-button-'+name)
.attr('title', cmd.title)
.append('<span class="elfinder-button-icon elfinder-button-icon-'+name+'"/>', text)
.on('mouseenter mouseleave', function(e) { !button.hasClass(disabled) && button.toggleClass(hover, e.type === 'mouseenter'); })
.on('click', function(e) {
if (!button.hasClass(disabled)) {
e.stopPropagation();
menu.is(':hidden') && fm.getUI().click();
menu.css(getMenuOffset()).slideToggle({
duration: 100,
done: function(e) {
fm[menu.is(':visible')? 'toFront' : 'toHide'](menu);
}
});
}
}),
hide = function() { fm.toHide(menu); },
menu = $('<div class="ui-front ui-widget ui-widget-content elfinder-button-menu ui-corner-all"/>')
.hide()
.appendTo(fm.getUI())
.on('mouseenter mouseleave', '.'+item, function(e) { $(this).toggleClass(hover, e.type === 'mouseenter'); })
.on('click', function(e) {
e.preventDefault();
e.stopPropagation();
})
.on('close', hide),
update = function() {
menu.children('[rel]').removeClass(selected+' '+asc+' '+desc)
.filter('[rel="'+fm.sortType+'"]')
.addClass(selected+' '+(fm.sortOrder == 'asc' ? asc : desc));
menu.children('.elfinder-sort-stick').toggleClass(selected, fm.sortStickFolders);
menu.children('.elfinder-sort-tree').toggleClass(selected, fm.sortAlsoTreeview);
},
getMenuOffset = function() {
var baseOffset = fm.getUI().offset(),
buttonOffset = button.offset();
return {
top : buttonOffset.top - baseOffset.top,
left : buttonOffset.left - baseOffset.left
};
},
tm;
text.hide();
$.each(fm.sortRules, function(name, value) {
menu.append($('<div class="'+item+'" rel="'+name+'"><span class="ui-icon ui-icon-arrowthick-1-n"/><span class="ui-icon ui-icon-arrowthick-1-s"/>'+fm.i18n('sort'+name)+'</div>').data('type', name));
});
menu.children().on('click', function(e) {
cmd.exec([], $(this).removeClass(hover).attr('rel'));
});
$('<div class="'+item+' '+item+'-separated elfinder-sort-ext elfinder-sort-stick"><span class="ui-icon ui-icon-check"/>'+fm.i18n('sortFoldersFirst')+'</div>')
.appendTo(menu)
.on('click', function() {
cmd.exec([], 'stick');
});
if ($.fn.elfindertree && $.inArray('tree', fm.options.ui) !== -1) {
$('<div class="'+item+' '+item+'-separated elfinder-sort-ext elfinder-sort-tree"><span class="ui-icon ui-icon-check"/>'+fm.i18n('sortAlsoTreeview')+'</div>')
.appendTo(menu)
.on('click', function() {
cmd.exec([], 'tree');
});
}
fm.bind('disable select', hide).getUI().on('click', hide);
fm.bind('open', function() {
menu.children('[rel]').each(function() {
var $this = $(this);
$this.toggle(fm.sorters[$this.attr('rel')]);
});
}).bind('sortchange', update);
if (menu.children().length > 1) {
cmd.change(function() {
tm && cancelAnimationFrame(tm);
tm = requestAnimationFrame(function() {
button.toggleClass(disabled, cmd.disabled());
update();
});
})
.change();
} else {
button.addClass(disabled);
}
});
};
/*
* File: /js/ui/stat.js
*/
/**
* @class elFinder ui
* Display number of files/selected files and its size in statusbar
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfinderstat = function(fm) {
return this.each(function() {
var size = $(this).addClass('elfinder-stat-size'),
sel = $('<div class="elfinder-stat-selected"/>')
.on('click', 'a', function(e) {
var hash = $(this).data('hash');
e.preventDefault();
fm.exec('opendir', [ hash ]);
}),
titleitems = fm.i18n('items'),
titlesel = fm.i18n('selected'),
titlesize = fm.i18n('size'),
setstat = function(files) {
var c = 0,
s = 0,
cwd = fm.cwd(),
calc = true,
hasSize = true;
if (cwd.sizeInfo || cwd.size) {
s = cwd.size;
calc = false;
}
$.each(files, function(i, file) {
c++;
if (calc) {
s += parseInt(file.size) || 0;
if (hasSize === true && file.mime === 'directory' && !file.sizeInfo) {
hasSize = false;
}
}
});
size.html(titleitems+': <span class="elfinder-stat-incsearch"></span>'+c+',&nbsp;<span class="elfinder-stat-size'+(hasSize? ' elfinder-stat-size-recursive' : '')+'">'+fm.i18n(hasSize? 'sum' : 'size')+': '+fm.formatSize(s)+'</span>')
.attr('title', size.text());
fm.trigger('uistatchange');
},
setIncsearchStat = function(data) {
size.find('span.elfinder-stat-incsearch').html(data? data.hashes.length + ' / ' : '');
size.attr('title', size.text());
fm.trigger('uistatchange');
},
setSelect = function(files) {
var s = 0,
c = 0,
dirs = [],
path, file;
if (files.length === 1) {
file = files[0];
s = file.size;
if (fm.searchStatus.state === 2) {
path = fm.escape(file.path? file.path.replace(/\/[^\/]*$/, '') : '..');
dirs.push('<a href="#elf_'+file.phash+'" data-hash="'+file.hash+'" title="'+path+'">'+path+'</a>');
}
dirs.push(fm.escape(file.i18 || file.name));
sel.html(dirs.join('/') + (s > 0 ? ', '+fm.formatSize(s) : ''));
} else if (files.length) {
$.each(files, function(i, file) {
c++;
s += parseInt(file.size)||0;
});
sel.html(c ? titlesel+': '+c+', '+titlesize+': '+fm.formatSize(s) : '&nbsp;');
} else {
sel.html('');
}
sel.attr('title', sel.text());
fm.trigger('uistatchange');
};
fm.getUI('statusbar').prepend(size).append(sel).show();
if (fm.UA.Mobile && $.fn.tooltip) {
fm.getUI('statusbar').tooltip({
classes: {
'ui-tooltip': 'elfinder-ui-tooltip ui-widget-shadow'
},
tooltipClass: 'elfinder-ui-tooltip ui-widget-shadow',
track: true
});
}
fm
.bind('cwdhasheschange', function(e) {
setstat($.map(e.data, function(h) { return fm.file(h); }));
})
.change(function(e) {
var files = e.data.changed || [],
cwdHash = fm.cwd().hash;
$.each(files, function() {
if (this.hash === cwdHash) {
if (this.size) {
size.children('.elfinder-stat-size').addClass('elfinder-stat-size-recursive').html(fm.i18n('sum')+': '+fm.formatSize(this.size));
size.attr('title', size.text());
}
return false;
}
});
})
.select(function() {
setSelect(fm.selectedFiles());
})
.bind('open', function() {
setSelect([]);
})
.bind('incsearch', function(e) {
setIncsearchStat(e.data);
})
.bind('incsearchend', function() {
setIncsearchStat();
})
;
});
};
/*
* File: /js/ui/toast.js
*/
/**
* @class elFinder toast
*
* This was created inspired by the toastr. Thanks to developers of toastr.
* CodeSeven/toastr: http://johnpapa.net <https://github.com/CodeSeven/toastr>
*
* @author Naoki Sawada
**/
$.fn.elfindertoast = function(opts, fm) {
var defOpts = Object.assign({
mode: 'success', // or 'info', 'warning' and 'error'
msg: '',
showMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery
showDuration: 300,
showEasing: 'swing', //swing and linear are built into jQuery
onShown: undefined,
hideMethod: 'fadeOut',
hideDuration: 1500,
hideEasing: 'swing',
onHidden: undefined,
timeOut: 3000,
extNode: undefined,
button: undefined,
width: undefined
}, $.isPlainObject(fm.options.uiOptions.toast.defaults)? fm.options.uiOptions.toast.defaults : {});
return this.each(function() {
opts = Object.assign({}, defOpts, opts || {});
var self = $(this),
show = function(notm) {
self.stop();
fm.toFront(self);
self[opts.showMethod]({
duration: opts.showDuration,
easing: opts.showEasing,
complete: function() {
opts.onShown && opts.onShown();
if (!notm && opts.timeOut) {
rmTm = setTimeout(rm, opts.timeOut);
}
}
});
},
rm = function() {
self[opts.hideMethod]({
duration: opts.hideDuration,
easing: opts.hideEasing,
complete: function() {
opts.onHidden && opts.onHidden();
self.remove();
}
});
},
rmTm;
self.on('click', function(e) {
e.stopPropagation();
e.preventDefault();
rmTm && clearTimeout(rmTm);
opts.onHidden && opts.onHidden();
self.stop().remove();
}).on('mouseenter mouseleave', function(e) {
if (opts.timeOut) {
rmTm && clearTimeout(rmTm);
rmTm = null;
if (e.type === 'mouseenter') {
show(true);
} else {
rmTm = setTimeout(rm, opts.timeOut);
}
}
}).hide().addClass('toast-' + opts.mode).append($('<div class="elfinder-toast-msg"/>').html(opts.msg.replace(/%([a-zA-Z0-9]+)%/g, function(m, m1) {
return fm.i18n(m1);
})));
if (opts.extNode) {
self.append(opts.extNode);
}
if (opts.button) {
self.append(
$('<button class="ui-button ui-widget ui-state-default ui-corner-all elfinder-tabstop"/>')
.append($('<span class="ui-button-text"/>').text(fm.i18n(opts.button.text)))
.on('mouseenter mouseleave', function(e) {
$(this).toggleClass('ui-state-hover', e.type == 'mouseenter');
})
.on('click', opts.button.click || function(){})
);
}
if (opts.width) {
self.css('max-width', opts.width);
}
show();
});
};
/*
* File: /js/ui/toolbar.js
*/
/**
* @class elFinder toolbar
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfindertoolbar = function(fm, opts) {
this.not('.elfinder-toolbar').each(function() {
var commands = fm._commands,
self = $(this).addClass('ui-helper-clearfix ui-widget-header elfinder-toolbar'),
options = {
// default options
displayTextLabel: false,
labelExcludeUA: ['Mobile'],
autoHideUA: ['Mobile'],
showPreferenceButton: 'none'
},
filter = function(opts) {
return $.grep(opts, function(v) {
if ($.isPlainObject(v)) {
options = Object.assign(options, v);
return false;
}
return true;
});
},
render = function(disabled){
var name,cmdPref;
$.each(buttons, function(i, b) { b.detach(); });
self.empty();
l = panels.length;
while (l--) {
if (panels[l]) {
panel = $('<div class="ui-widget-content ui-corner-all elfinder-buttonset"/>');
i = panels[l].length;
while (i--) {
name = panels[l][i];
if ((!disabled || !disabled[name]) && (cmd = commands[name])) {
button = 'elfinder'+cmd.options.ui;
if (! buttons[name] && $.fn[button]) {
buttons[name] = $('<div/>')[button](cmd);
}
if (buttons[name]) {
buttons[name].children('.elfinder-button-text')[textLabel? 'show' : 'hide']();
panel.prepend(buttons[name]);
}
}
}
panel.children().length && self.prepend(panel);
panel.children(':gt(0)').before('<span class="ui-widget-content elfinder-toolbar-button-separator"/>');
}
}
if (cmdPref = commands['preference']) {
//cmdPref.state = !self.children().length? 0 : -1;
if (options.showPreferenceButton === 'always' || (!self.children().length && options.showPreferenceButton === 'auto')) {
//cmdPref.state = 0;
panel = $('<div class="ui-widget-content ui-corner-all elfinder-buttonset"/>');
name = 'preference';
button = 'elfinder'+cmd.options.ui;
buttons[name] = $('<div/>')[button](cmdPref);
buttons[name].children('.elfinder-button-text')[textLabel? 'show' : 'hide']();
panel.prepend(buttons[name]);
self.append(panel);
}
}
(! self.data('swipeClose') && self.children().length)? self.show() : self.hide();
prevHeight = self[0].clientHeight;
fm.trigger('toolbarload').trigger('uiresize');
},
buttons = {},
panels = filter(opts || []),
dispre = null,
uiCmdMapPrev = '',
prevHeight = 0,
contextRaw = [],
l, i, cmd, panel, button, swipeHandle, autoHide, textLabel, resizeTm;
// normalize options
options.showPreferenceButton = options.showPreferenceButton.toLowerCase();
if (options.displayTextLabel !== 'none') {
// correction of options.displayTextLabel
textLabel = fm.storage('toolbarTextLabel');
if (textLabel === null) {
textLabel = (options.displayTextLabel && (! options.labelExcludeUA || ! options.labelExcludeUA.length || ! $.grep(options.labelExcludeUA, function(v){ return fm.UA[v]? true : false; }).length));
} else {
textLabel = (textLabel == 1);
}
contextRaw.push({
label : fm.i18n('textLabel'),
icon : 'text',
callback : function() {
textLabel = ! textLabel;
self.css('height', '').find('.elfinder-button-text')[textLabel? 'show':'hide']();
fm.trigger('uiresize').storage('toolbarTextLabel', textLabel? '1' : '0');
},
});
}
if (options.preferenceInContextmenu && commands['preference']) {
contextRaw.push({
label : fm.i18n('toolbarPref'),
icon : 'preference',
callback : function() {
fm.exec('preference', void(0), {tab: 'toolbar'});
}
});
}
// add contextmenu
if (contextRaw.length) {
self.on('contextmenu', function(e) {
e.stopPropagation();
e.preventDefault();
fm.trigger('contextmenu', {
raw: contextRaw,
x: e.pageX,
y: e.pageY
});
}).on('touchstart', function(e) {
if (e.originalEvent.touches.length > 1) {
return;
}
self.data('tmlongtap') && clearTimeout(self.data('tmlongtap'));
self.removeData('longtap')
.data('longtap', {x: e.originalEvent.touches[0].pageX, y: e.originalEvent.touches[0].pageY})
.data('tmlongtap', setTimeout(function() {
self.removeData('longtapTm')
.trigger({
type: 'contextmenu',
pageX: self.data('longtap').x,
pageY: self.data('longtap').y
})
.data('longtap', {longtap: true});
}, 500));
}).on('touchmove touchend', function(e) {
if (self.data('tmlongtap')) {
if (e.type === 'touchend' ||
( Math.abs(self.data('longtap').x - e.originalEvent.touches[0].pageX)
+ Math.abs(self.data('longtap').y - e.originalEvent.touches[0].pageY)) > 4)
clearTimeout(self.data('tmlongtap'));
self.removeData('longtapTm');
}
}).on('click', function(e) {
if (self.data('longtap') && self.data('longtap').longtap) {
e.stopImmediatePropagation();
e.preventDefault();
}
}).on('touchend click', '.elfinder-button', function(e) {
if (self.data('longtap') && self.data('longtap').longtap) {
e.stopImmediatePropagation();
e.preventDefault();
}
}
);
}
self.prev().length && self.parent().prepend(this);
render();
fm.bind('open sync select toolbarpref', function() {
var disabled = Object.assign({}, fm.option('disabledFlip')),
userHides = fm.storage('toolbarhides'),
doRender, sel, disabledKeys;
if (! userHides && Array.isArray(options.defaultHides)) {
userHides = {};
$.each(options.defaultHides, function() {
userHides[this] = true;
});
fm.storage('toolbarhides', userHides);
}
if (this.type === 'select') {
if (fm.searchStatus.state < 2) {
return;
}
sel = fm.selected();
if (sel.length) {
disabled = fm.getDisabledCmds(sel, true);
}
}
$.each(userHides, function(n) {
if (!disabled[n]) {
disabled[n] = true;
}
});
if (Object.keys(fm.commandMap).length) {
$.each(fm.commandMap, function(from, to){
if (to === 'hidden') {
disabled[from] = true;
}
});
}
disabledKeys = Object.keys(disabled);
if (!dispre || dispre.toString() !== disabledKeys.sort().toString()) {
render(disabledKeys.length? disabled : null);
doRender = true;
}
dispre = disabledKeys.sort();
if (doRender || uiCmdMapPrev !== JSON.stringify(fm.commandMap)) {
uiCmdMapPrev = JSON.stringify(fm.commandMap);
if (! doRender) {
// reset toolbar
$.each($('div.elfinder-button'), function(){
var origin = $(this).data('origin');
if (origin) {
$(this).after(origin).detach();
}
});
}
if (Object.keys(fm.commandMap).length) {
$.each(fm.commandMap, function(from, to){
var cmd = fm._commands[to],
button = cmd? 'elfinder'+cmd.options.ui : null,
btn;
if (button && $.fn[button]) {
btn = buttons[from];
if (btn) {
if (! buttons[to] && $.fn[button]) {
buttons[to] = $('<div/>')[button](cmd);
if (buttons[to]) {
buttons[to].children('.elfinder-button-text')[textLabel? 'show' : 'hide']();
if (cmd.extendsCmd) {
buttons[to].children('span.elfinder-button-icon').addClass('elfinder-button-icon-' + cmd.extendsCmd);
}
}
}
if (buttons[to]) {
btn.after(buttons[to]);
buttons[to].data('origin', btn.detach());
}
}
}
});
}
}
}).bind('resize', function(e) {
resizeTm && cancelAnimationFrame(resizeTm);
resizeTm = requestAnimationFrame(function() {
var h = self[0].clientHeight;
if (prevHeight !== h) {
prevHeight = h;
fm.trigger('uiresize');
}
});
});
if (fm.UA.Touch) {
autoHide = fm.storage('autoHide') || {};
if (typeof autoHide.toolbar === 'undefined') {
autoHide.toolbar = (options.autoHideUA && options.autoHideUA.length > 0 && $.grep(options.autoHideUA, function(v){ return fm.UA[v]? true : false; }).length);
fm.storage('autoHide', autoHide);
}
if (autoHide.toolbar) {
fm.one('init', function() {
fm.uiAutoHide.push(function(){ self.stop(true, true).trigger('toggle', { duration: 500, init: true }); });
});
}
fm.bind('load', function() {
swipeHandle = $('<div class="elfinder-toolbar-swipe-handle"/>').hide().appendTo(fm.getUI());
if (swipeHandle.css('pointer-events') !== 'none') {
swipeHandle.remove();
swipeHandle = null;
}
});
self.on('toggle', function(e, data) {
var wz = fm.getUI('workzone'),
toshow= self.is(':hidden'),
wzh = wz.height(),
h = self.height(),
tbh = self.outerHeight(true),
delta = tbh - h,
opt = Object.assign({
step: function(now) {
wz.height(wzh + (toshow? (now + delta) * -1 : h - now));
fm.trigger('resize');
},
always: function() {
requestAnimationFrame(function() {
self.css('height', '');
fm.trigger('uiresize');
if (swipeHandle) {
if (toshow) {
swipeHandle.stop(true, true).hide();
} else {
swipeHandle.height(data.handleH? data.handleH : '');
fm.resources.blink(swipeHandle, 'slowonce');
}
}
toshow && self.scrollTop('0px');
data.init && fm.trigger('uiautohide');
});
}
}, data);
self.data('swipeClose', ! toshow).stop(true, true).animate({height : 'toggle'}, opt);
autoHide.toolbar = !toshow;
fm.storage('autoHide', Object.assign(fm.storage('autoHide'), {toolbar: autoHide.toolbar}));
}).on('touchstart', function(e) {
if (self.scrollBottom() > 5) {
e.originalEvent._preventSwipeY = true;
}
});
}
});
return this;
};
/*
* File: /js/ui/tree.js
*/
/**
* @class elFinder folders tree
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfindertree = function(fm, opts) {
var treeclass = fm.res('class', 'tree');
this.not('.'+treeclass).each(function() {
var c = 'class', mobile = fm.UA.Mobile,
/**
* Root directory class name
*
* @type String
*/
root = fm.res(c, 'treeroot'),
/**
* Open root dir if not opened yet
*
* @type Boolean
*/
openRoot = opts.openRootOnLoad,
/**
* Open current work dir if not opened yet
*
* @type Boolean
*/
openCwd = opts.openCwdOnOpen,
/**
* Auto loading current directory parents and do expand their node
*
* @type Boolean
*/
syncTree = openCwd || opts.syncTree,
/**
* Subtree class name
*
* @type String
*/
subtree = fm.res(c, 'navsubtree'),
/**
* Directory class name
*
* @type String
*/
navdir = fm.res(c, 'treedir'),
/**
* Directory CSS selector
*
* @type String
*/
selNavdir = 'span.' + navdir,
/**
* Collapsed arrow class name
*
* @type String
*/
collapsed = fm.res(c, 'navcollapse'),
/**
* Expanded arrow class name
*
* @type String
*/
expanded = fm.res(c, 'navexpand'),
/**
* Class name to mark arrow for directory with already loaded children
*
* @type String
*/
loaded = 'elfinder-subtree-loaded',
/**
* Class name to mark need subdirs request
*
* @type String
*/
chksubdir = 'elfinder-subtree-chksubdir',
/**
* Arraw class name
*
* @type String
*/
arrow = fm.res(c, 'navarrow'),
/**
* Current directory class name
*
* @type String
*/
active = fm.res(c, 'active'),
/**
* Droppable dirs dropover class
*
* @type String
*/
dropover = fm.res(c, 'adroppable'),
/**
* Hover class name
*
* @type String
*/
hover = fm.res(c, 'hover'),
/**
* Disabled dir class name
*
* @type String
*/
disabled = fm.res(c, 'disabled'),
/**
* Draggable dir class name
*
* @type String
*/
draggable = fm.res(c, 'draggable'),
/**
* Droppable dir class name
*
* @type String
*/
droppable = fm.res(c, 'droppable'),
/**
* root wrapper class
*
* @type String
*/
wrapperRoot = 'elfinder-navbar-wrapper-root',
/**
* Un-disabled cmd `paste` volume's root wrapper class
*
* @type String
*/
pastable = 'elfinder-navbar-wrapper-pastable',
/**
* Un-disabled cmd `upload` volume's root wrapper class
*
* @type String
*/
uploadable = 'elfinder-navbar-wrapper-uploadable',
/**
* Is position x inside Navbar
*
* @param x Numbar
*
* @return
*/
insideNavbar = function(x) {
var left = navbar.offset().left;
return left <= x && x <= left + navbar.width();
},
/**
* To call subdirs elements queue
*
* @type Object
*/
subdirsQue = {},
/**
* To exec subdirs elements ids
*
*/
subdirsExecQue = [],
/**
* Request subdirs to backend
*
* @param id String
*
* @return Deferred
*/
subdirs = function(ids) {
var targets = [];
$.each(ids, function(i, id) {
subdirsQue[id] && targets.push(fm.navId2Hash(id));
delete subdirsQue[id];
});
if (targets.length) {
return fm.request({
data: {
cmd: 'subdirs',
targets: targets,
preventDefault : true
}
}).done(function(res) {
if (res && res.subdirs) {
$.each(res.subdirs, function(hash, subdirs) {
var elm = $('#'+fm.navHash2Id(hash));
elm.removeClass(chksubdir);
elm[subdirs? 'addClass' : 'removeClass'](collapsed);
});
}
});
}
},
subdirsJobRes = null,
/**
* To check target element is in window of subdirs
*
* @return void
*/
checkSubdirs = function() {
var ids = Object.keys(subdirsQue);
if (ids.length) {
subdirsJobRes && subdirsJobRes._abort();
execSubdirsTm && clearTimeout(execSubdirsTm);
subdirsExecQue = [];
subdirsJobRes = fm.asyncJob(function(id) {
return fm.isInWindow($('#'+id))? id : null;
}, ids, { numPerOnce: 200 })
.done(function(arr) {
if (arr.length) {
subdirsExecQue = arr;
execSubdirs();
}
});
}
},
subdirsPending = 0,
execSubdirsTm,
/**
* Exec subdirs as batch request
*
* @return void
*/
execSubdirs = function() {
var cnt = opts.subdirsMaxConn - subdirsPending,
atOnce = fm.maxTargets? Math.min(fm.maxTargets, opts.subdirsAtOnce) : opts.subdirsAtOnce,
i, ids;
execSubdirsTm && cancelAnimationFrame(execSubdirsTm);
if (subdirsExecQue.length) {
if (cnt > 0) {
for (i = 0; i < cnt; i++) {
if (subdirsExecQue.length) {
subdirsPending++;
subdirs(subdirsExecQue.splice(0, atOnce)).always(function() {
subdirsPending--;
execSubdirs();
});
}
}
} else {
execSubdirsTm = requestAnimationFrame(function() {
subdirsExecQue.length && execSubdirs();
});
}
}
},
drop = fm.droppable.drop,
/**
* Droppable options
*
* @type Object
*/
droppableopts = $.extend(true, {}, fm.droppable, {
// show subfolders on dropover
over : function(e, ui) {
var dst = $(this),
helper = ui.helper,
cl = hover+' '+dropover,
hash, status;
e.stopPropagation();
helper.data('dropover', helper.data('dropover') + 1);
dst.data('dropover', true);
if (ui.helper.data('namespace') !== fm.namespace || ! insideNavbar(e.clientX) || ! fm.insideWorkzone(e.pageX, e.pageY)) {
dst.removeClass(cl);
helper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus');
return;
}
dst.addClass(hover);
if (dst.is('.'+collapsed+':not(.'+expanded+')')) {
dst.data('expandTimer', setTimeout(function() {
dst.is('.'+collapsed+'.'+hover) && dst.children('.'+arrow).trigger('click');
}, 500));
}
if (dst.is('.elfinder-ro,.elfinder-na')) {
dst.removeClass(dropover);
helper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus');
return;
}
hash = fm.navId2Hash(dst.attr('id'));
dst.data('dropover', hash);
$.each(ui.helper.data('files'), function(i, h) {
if (h === hash || (fm.file(h).phash === hash && !ui.helper.hasClass('elfinder-drag-helper-plus'))) {
dst.removeClass(cl);
return false; // break $.each
}
});
if (helper.data('locked')) {
status = 'elfinder-drag-helper-plus';
} else {
status = 'elfinder-drag-helper-move';
if (e.shiftKey || e.ctrlKey || e.metaKey) {
status += ' elfinder-drag-helper-plus';
}
}
dst.hasClass(dropover) && helper.addClass(status);
requestAnimationFrame(function(){ dst.hasClass(dropover) && helper.addClass(status); });
},
out : function(e, ui) {
var dst = $(this),
helper = ui.helper;
e.stopPropagation();
helper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus').data('dropover', Math.max(helper.data('dropover') - 1, 0));
dst.data('expandTimer') && clearTimeout(dst.data('expandTimer'));
dst.removeData('dropover')
.removeClass(hover+' '+dropover);
},
deactivate : function() {
$(this).removeData('dropover')
.removeClass(hover+' '+dropover);
},
drop : function(e, ui) {
insideNavbar(e.clientX) && drop.call(this, e, ui);
}
}),
spinner = $(fm.res('tpl', 'navspinner')),
/**
* Directory html template
*
* @type String
*/
tpl = fm.res('tpl', 'navdir'),
/**
* Permissions marker html template
*
* @type String
*/
ptpl = fm.res('tpl', 'perms'),
/**
* Lock marker html template
*
* @type String
*/
ltpl = fm.res('tpl', 'lock'),
/**
* Symlink marker html template
*
* @type String
*/
stpl = fm.res('tpl', 'symlink'),
/**
* Directory hashes that has more pages
*
* @type Object
*/
hasMoreDirs = {},
/**
* Html template replacement methods
*
* @type Object
*/
replace = {
id : function(dir) { return fm.navHash2Id(dir.hash); },
name : function(dir) { return fm.escape(dir.i18 || dir.name); },
cssclass : function(dir) {
var cname = (dir.phash && ! dir.isroot ? '' : root)+' '+navdir+' '+fm.perms2class(dir);
dir.dirs && !dir.link && (cname += ' ' + collapsed) && dir.dirs == -1 && (cname += ' ' + chksubdir);
opts.getClass && (cname += ' ' + opts.getClass(dir));
dir.csscls && (cname += ' ' + fm.escape(dir.csscls));
return cname;
},
root : function(dir) {
var cls = '';
if (!dir.phash || dir.isroot) {
cls += ' '+wrapperRoot;
if (!dir.disabled || dir.disabled.length < 1) {
cls += ' '+pastable+' '+uploadable;
} else {
if ($.inArray('paste', dir.disabled) === -1) {
cls += ' '+pastable;
}
if ($.inArray('upload', dir.disabled) === -1) {
cls += ' '+uploadable;
}
}
return cls;
} else {
return '';
}
},
permissions : function(dir) { return !dir.read || !dir.write ? ptpl : ''; },
symlink : function(dir) { return dir.alias ? stpl : ''; },
style : function(dir) { return dir.icon ? fm.getIconStyle(dir) : ''; }
},
/**
* Return html for given dir
*
* @param Object directory
* @return String
*/
itemhtml = function(dir) {
return tpl.replace(/(?:\{([a-z]+)\})/ig, function(m, key) {
var res = replace[key] ? replace[key](dir) : (dir[key] || '');
if (key === 'id' && dir.dirs == -1) {
subdirsQue[res] = res;
}
return res;
});
},
/**
* Return only dirs from files list
*
* @param Array files list
* @param Boolean do check exists
* @return Array
*/
filter = function(files, checkExists) {
return $.map(files || [], function(f) {
return (f.mime === 'directory' && (!checkExists || $('#'+fm.navHash2Id(f.hash)).length)) ? f : null;
});
},
/**
* Find parent subtree for required directory
*
* @param String dir hash
* @return jQuery
*/
findSubtree = function(hash) {
return hash ? $('#'+fm.navHash2Id(hash)).next('.'+subtree) : tree;
},
/**
* Find directory (wrapper) in required node
* before which we can insert new directory
*
* @param jQuery parent directory
* @param Object new directory
* @return jQuery
*/
findSibling = function(subtree, dir) {
var node = subtree.children(':first'),
info;
while (node.length) {
info = fm.file(fm.navId2Hash(node.children('[id]').attr('id')));
if ((info = fm.file(fm.navId2Hash(node.children('[id]').attr('id'))))
&& compare(dir, info) < 0) {
return node;
}
node = node.next();
}
return subtree.children('button.elfinder-navbar-pager-next');
},
/**
* Add new dirs in tree
*
* @param Array dirs list
* @return void
*/
updateTree = function(dirs) {
var length = dirs.length,
orphans = [],
i = length,
tgts = $(),
done = {},
cwd = fm.cwd(),
append = function(parent, dirs, start, direction) {
var hashes = {},
curStart = 0,
max = fm.newAPI? Math.min(10000, Math.max(10, opts.subTreeMax)) : 10000,
setHashes = function() {
hashes = {};
$.each(dirs, function(i, d) {
hashes[d.hash] = i;
});
},
change = function(mode) {
if (mode === 'prepare') {
$.each(dirs, function(i, d) {
d.node && parent.append(d.node.hide());
});
} else if (mode === 'done') {
$.each(dirs, function(i, d) {
d.node && d.node.detach().show();
});
}
},
update = function(e, data) {
var i, changed;
e.stopPropagation();
if (data.select) {
render(getStart(data.select));
return;
}
if (data.change) {
change(data.change);
return;
}
if (data.removed && data.removed.length) {
dirs = $.grep(dirs, function(d) {
if (data.removed.indexOf(d.hash) === -1) {
return true;
} else {
!changed && (changed = true);
return false;
}
});
}
if (data.added && data.added.length) {
dirs = dirs.concat($.grep(data.added, function(d) {
if (hashes[d.hash] === void(0)) {
!changed && (changed = true);
return true;
} else {
return false;
}
}));
}
if (changed) {
dirs.sort(compare);
setHashes();
render(curStart);
}
},
getStart = function(target) {
if (hashes[target] !== void(0)) {
return Math.floor(hashes[target] / max) * max;
}
return void(0);
},
target = fm.navId2Hash(parent.prev('[id]').attr('id')),
render = function(start, direction) {
var html = [],
nodes = {},
total, page, s, parts, prev, next, prevBtn, nextBtn;
delete hasMoreDirs[target];
curStart = start;
parent.off('update.'+fm.namespace, update);
if (dirs.length > max) {
parent.on('update.'+fm.namespace, update);
if (start === void(0)) {
s = 0;
setHashes();
start = getStart(cwd.hash);
if (start === void(0)) {
start = 0;
}
}
parts = dirs.slice(start, start + max);
hasMoreDirs[target] = parent;
prev = start? Math.max(-1, start - max) : -1;
next = (start + max >= dirs.length)? 0 : start + max;
total = Math.ceil(dirs.length/max);
page = Math.ceil(start/max);
}
$.each(parts || dirs, function(i, d) {
html.push(itemhtml(d));
if (d.node) {
nodes[d.hash] = d.node;
}
});
if (prev > -1) {
prevBtn = $('<button class="elfinder-navbar-pager elfinder-navbar-pager-prev"/>')
.text(fm.i18n('btnPrevious', page, total))
.button({
icons: {
primary: "ui-icon-caret-1-n"
}
})
.on('click', function(e) {
e.preventDefault();
e.stopPropagation();
render(prev, 'up');
});
} else {
prevBtn = $();
}
if (next) {
nextBtn = $('<button class="elfinder-navbar-pager elfinder-navbar-pager-next"/>')
.text(fm.i18n('btnNext', page + 2, total))
.button({
icons: {
primary: "ui-icon-caret-1-s"
}
})
.on('click', function(e) {
e.preventDefault();
e.stopPropagation();
render(next, 'down');
});
} else {
nextBtn = $();
}
detach();
parent.empty()[parts? 'addClass' : 'removeClass']('elfinder-navbar-hasmore').append(prevBtn, html.join(''), nextBtn);
$.each(nodes, function(h, n) {
$('#'+fm.navHash2Id(h)).parent().replaceWith(n);
});
if (direction) {
autoScroll(fm.navHash2Id(parts[direction === 'up'? parts.length - 1 : 0].hash));
}
! mobile && fm.lazy(function() { updateDroppable(null, parent); });
},
detach = function() {
$.each(parent.children('.elfinder-navbar-wrapper'), function(i, elm) {
var n = $(elm),
ch = n.children('[id]:first'),
h, c;
if (ch.hasClass(loaded)) {
h = fm.navId2Hash(ch.attr('id'));
if (h && (c = hashes[h]) !== void(0)) {
dirs[c].node = n.detach();
}
}
});
};
render();
},
dir, html, parent, sibling, init, atonce = {}, updates = [], base, node,
firstVol = true; // check for netmount volume
while (i--) {
dir = dirs[i];
if (done[dir.hash] || $('#'+fm.navHash2Id(dir.hash)).length) {
continue;
}
done[dir.hash] = true;
if ((parent = findSubtree(dir.phash)).length) {
if (dir.phash && ((init = !parent.children().length) || parent.hasClass('elfinder-navbar-hasmore') || (sibling = findSibling(parent, dir)).length)) {
if (init) {
if (!atonce[dir.phash]) {
atonce[dir.phash] = [];
}
atonce[dir.phash].push(dir);
} else {
if (sibling) {
node = itemhtml(dir);
sibling.before(node);
! mobile && (tgts = tgts.add(node));
} else {
updates.push(dir);
}
}
} else {
node = itemhtml(dir);
parent[firstVol || dir.phash ? 'append' : 'prepend'](node);
firstVol = false;
if (!dir.phash || dir.isroot) {
base = $('#'+fm.navHash2Id(dir.hash)).parent();
}
! mobile && updateDroppable(null, base);
}
} else {
orphans.push(dir);
}
}
// When init, html append at once
if (Object.keys(atonce).length){
$.each(atonce, function(p, dirs){
var parent = findSubtree(p),
html = [];
dirs.sort(compare);
append(parent, dirs);
});
}
if (updates.length) {
parent.trigger('update.' + fm.namespace, { added : updates });
}
if (orphans.length && orphans.length < length) {
updateTree(orphans);
return;
}
! mobile && tgts.length && fm.lazy(function() { updateDroppable(tgts); });
},
/**
* sort function by dir.name
*
*/
compare = function(dir1, dir2) {
if (! fm.sortAlsoTreeview) {
return fm.sortRules.name(dir1, dir2);
} else {
var asc = fm.sortOrder == 'asc',
type = fm.sortType,
rules = fm.sortRules,
res;
res = asc? rules[fm.sortType](dir1, dir2) : rules[fm.sortType](dir2, dir1);
return type !== 'name' && res === 0
? res = asc ? rules.name(dir1, dir2) : rules.name(dir2, dir1)
: res;
}
},
/**
* Timer ID of autoScroll
*
* @type Integer
*/
autoScrTm,
/**
* Auto scroll to cwd
*
* @return Object jQuery Deferred
*/
autoScroll = function(target) {
var dfrd = $.Deferred(),
current, parent, top, treeH, bottom, tgtTop;
autoScrTm && clearTimeout(autoScrTm);
autoScrTm = setTimeout(function() {
current = $('#'+(target || fm.navHash2Id(fm.cwd().hash)));
if (current.length) {
// expand parents directory
(openCwd? current : current.parent()).parents('.elfinder-navbar-wrapper').children('.'+loaded).addClass(expanded).next('.'+subtree).show();
parent = tree.parent().stop(false, true);
top = parent.offset().top;
treeH = parent.height();
bottom = top + treeH - current.outerHeight();
tgtTop = current.offset().top;
if (tgtTop < top || tgtTop > bottom) {
parent.animate({
scrollTop : parent.scrollTop() + tgtTop - top - treeH / 3
}, {
duration : opts.durations.autoScroll,
complete : function() { dfrd.resolve(); }
});
} else {
dfrd.resolve();
}
} else {
dfrd.reject();
}
}, 100);
return dfrd;
},
/**
* Get hashes array of items of the bottom of the leaf root back from the target
*
* @param Object elFinder item(directory) object
* @return Array hashes
*/
getEnds = function(d) {
var cur = d || fm.cwd(),
res = cur.hash? [ cur.hash ] : [],
phash, root, dir;
root = fm.root(cur.hash);
dir = fm.file(root);
while (dir && (phash = dir.phash)) {
res.unshift(phash);
root = fm.root(phash);
dir = fm.file(root);
if ($('#'+fm.navHash2Id(dir.hash)).hasClass(loaded)) {
break;
}
}
return res;
},
/**
* Select pages back in order to display the target
*
* @param Object elFinder item(directory) object
* @return Object jQuery node object of target node
*/
selectPages = function(current) {
var cur = current || fm.cwd(),
curHash = cur.hash,
node = $('#'+fm.navHash2Id(curHash));
if (!node.length) {
while(cur && cur.phash) {
if (hasMoreDirs[cur.phash] && !$('#'+fm.navHash2Id(cur.hash)).length) {
hasMoreDirs[cur.phash].trigger('update.'+fm.namespace, { select : cur.hash });
}
cur = fm.file(cur.phash);
}
node = $('#'+fm.navHash2Id(curHash));
}
return node;
},
/**
* Flag indicating that synchronization is currently in progress
*
* @type Boolean
*/
syncing,
/**
* Mark current directory as active
* If current directory is not in tree - load it and its parents
*
* @param Array directory objects of cwd
* @param Boolean do auto scroll
* @return Object jQuery Deferred
*/
sync = function(cwdDirs, aScr) {
var cwd = fm.cwd(),
cwdhash = cwd.hash,
autoScr = aScr === void(0)? syncTree : aScr,
loadParents = function(dir) {
var dfd = $.Deferred(),
reqs = [],
ends = getEnds(dir),
makeReq = function(cmd, h, until) {
var data = {
cmd : cmd,
target : h
};
if (until) {
data.until = until;
}
return fm.request({
data : data,
preventFail : true
});
},
baseHash, baseId;
reqs = $.map(ends, function(h) {
var d = fm.file(h),
isRoot = d? fm.isRoot(d) : false,
node = $('#'+fm.navHash2Id(h)),
getPhash = function(h, dep) {
var d, ph,
depth = dep || 1;
ph = (d = fm.file(h))? d.phash : false;
if (ph && depth > 1) {
return getPhash(ph, --depth);
}
return ph;
},
until,
closest = (function() {
var phash = getPhash(h);
until = phash;
while (phash) {
if ($('#'+fm.navHash2Id(phash)).hasClass(loaded)) {
break;
}
until = phash;
phash = getPhash(phash);
}
if (!phash) {
until = void(0);
phash = fm.root(h);
}
return phash;
})(),
cmd;
if (!node.hasClass(loaded) && (isRoot || !d || !$('#'+fm.navHash2Id(d.phash)).hasClass(loaded))) {
if (isRoot || closest === getPhash(h) || closest === getPhash(h, 2)) {
until = void(0);
cmd = 'tree';
if (!isRoot) {
h = getPhash(h);
}
} else {
cmd = 'parents';
}
if (!baseHash) {
baseHash = (cmd === 'tree')? h : closest;
}
return makeReq(cmd, h, until);
}
return null;
});
if (reqs.length) {
selectPages(fm.file(baseHash));
baseId = fm.navHash2Id(baseHash);
autoScr && autoScroll(baseId);
baseNode = $('#'+baseId);
spinner = $(fm.res('tpl', 'navspinner')).insertBefore(baseNode.children('.'+arrow));
baseNode.removeClass(collapsed);
$.when.apply($, reqs)
.done(function() {
var res = {},data, treeDirs, dirs, argLen, i;
argLen = arguments.length;
if (argLen > 0) {
for (i = 0; i < argLen; i++) {
data = arguments[i].tree || [];
res[ends[i]] = Object.assign([], filter(data));
}
}
dfd.resolve(res);
})
.fail(function() {
dfd.reject();
});
return dfd;
} else {
return dfd.resolve();
}
},
done= function(res, dfrd) {
var open = function() {
if (openRoot && baseNode) {
findSubtree(baseNode.hash).show().prev(selNavdir).addClass(expanded);
openRoot = false;
}
if (autoScr) {
autoScroll().done(checkSubdirs);
} else {
checkSubdirs();
}
},
current;
if (res) {
$.each(res, function(endHash, dirs) {
dirs && updateTree(dirs);
selectPages(fm.file(endHash));
dirs && updateArrows(dirs, loaded);
});
}
if (cwdDirs) {
(fm.api < 2.1) && cwdDirs.push(cwd);
updateTree(cwdDirs);
}
// set current node
current = selectPages();
if (!current.hasClass(active)) {
tree.find(selNavdir+'.'+active).removeClass(active);
current.addClass(active);
}
// mark as loaded to cwd parents
current.parents('.elfinder-navbar-wrapper').children('.'+navdir).addClass(loaded);
if (res) {
fm.lazy(open).done(function() {
dfrd.resolve();
});
} else {
open();
dfrd.resolve();
}
},
rmSpinner = function(fail) {
if (baseNode) {
spinner.remove();
baseNode.addClass(collapsed + (fail? '' : (' ' + loaded)));
}
},
dfrd = $.Deferred(),
baseNode, spinner;
if (!$('#'+fm.navHash2Id(cwdhash)).length) {
syncing = true;
loadParents()
.done(function(res) {
done(res, dfrd);
rmSpinner();
})
.fail(function() {
rmSpinner(true);
dfrd.reject();
})
.always(function() {
syncing = false;
});
} else {
done(void(0), dfrd);
}
// trigger 'treesync' with my $.Deferred
fm.trigger('treesync', dfrd);
return dfrd;
},
/**
* Make writable and not root dirs droppable
*
* @return void
*/
updateDroppable = function(target, node) {
var limit = 100,
next;
if (!target) {
if (!node || node.closest('div.'+wrapperRoot).hasClass(uploadable)) {
(node || tree.find('div.'+uploadable)).find(selNavdir+':not(.elfinder-ro,.elfinder-na)').addClass('native-droppable');
}
if (!node || node.closest('div.'+wrapperRoot).hasClass(pastable)) {
target = (node || tree.find('div.'+pastable)).find(selNavdir+':not(.'+droppable+')');
} else {
target = $();
}
if (node) {
// check leaf roots
node.children('div.'+wrapperRoot).each(function() {
updateDroppable(null, $(this));
});
}
}
// make droppable on async
if (target.length) {
fm.asyncJob(function(elm) {
$(elm).droppable(droppableopts);
}, $.makeArray(target), {
interval : 20,
numPerOnce : 100
});
}
},
/**
* Check required folders for subfolders and update arrow classes
*
* @param Array folders to check
* @param String css class
* @return void
*/
updateArrows = function(dirs, cls) {
var sel = cls == loaded
? '.'+collapsed+':not(.'+loaded+')'
: ':not(.'+collapsed+')';
$.each(dirs, function(i, dir) {
$('#'+fm.navHash2Id(dir.phash)+sel)
.filter(function() { return $.grep($(this).next('.'+subtree).children(), function(n) {
return ($(n).children().hasClass(root))? false : true;
}).length > 0; })
.addClass(cls);
});
},
/**
* Navigation tree
*
* @type JQuery
*/
tree = $(this).addClass(treeclass)
// make dirs draggable and toggle hover class
.on('mouseenter mouseleave', selNavdir, function(e) {
var enter = (e.type === 'mouseenter');
if (enter && scrolling) { return; }
var link = $(this);
if (!link.hasClass(dropover+' '+disabled)) {
if (!mobile && enter && !link.data('dragRegisted') && !link.hasClass(root+' '+draggable+' elfinder-na elfinder-wo')) {
link.data('dragRegisted', true);
if (fm.isCommandEnabled('copy', fm.navId2Hash(link.attr('id')))) {
link.draggable(fm.draggable);
}
}
link.toggleClass(hover, enter);
}
})
// native drag enter
.on('dragenter', selNavdir, function(e) {
if (e.originalEvent.dataTransfer) {
var dst = $(this);
dst.addClass(hover);
if (dst.is('.'+collapsed+':not(.'+expanded+')')) {
dst.data('expandTimer', setTimeout(function() {
dst.is('.'+collapsed+'.'+hover) && dst.children('.'+arrow).trigger('click');
}, 500));
}
}
})
// native drag leave
.on('dragleave', selNavdir, function(e) {
if (e.originalEvent.dataTransfer) {
var dst = $(this);
dst.data('expandTimer') && clearTimeout(dst.data('expandTimer'));
dst.removeClass(hover);
}
})
// open dir or open subfolders in tree
.on('click', selNavdir, function(e) {
var link = $(this),
hash = fm.navId2Hash(link.attr('id')),
file = fm.file(hash);
if (link.data('longtap')) {
link.removeData('longtap');
e.stopPropagation();
return;
}
if (!link.hasClass(active)) {
tree.find(selNavdir+'.'+active).removeClass(active);
link.addClass(active);
}
if (hash != fm.cwd().hash && !link.hasClass(disabled)) {
fm.exec('open', hash).done(function() {
fm.one('opendone', function() {
fm.select({selected: [hash], origin: 'navbar'});
});
});
} else {
if (link.hasClass(collapsed)) {
link.children('.'+arrow).trigger('click');
}
fm.select({selected: [hash], origin: 'navbar'});
}
})
// for touch device
.on('touchstart', selNavdir, function(e) {
if (e.originalEvent.touches.length > 1) {
return;
}
var evt = e.originalEvent,
p;
if (e.target.nodeName === 'INPUT') {
e.stopPropagation();
return;
}
p = $(this).addClass(hover)
.removeData('longtap')
.data('tmlongtap', setTimeout(function(e){
// long tap
p.data('longtap', true);
fm.trigger('contextmenu', {
'type' : 'navbar',
'targets' : [fm.navId2Hash(p.attr('id'))],
'x' : evt.touches[0].pageX,
'y' : evt.touches[0].pageY
});
}, 500));
})
.on('touchmove touchend', selNavdir, function(e) {
if (e.target.nodeName === 'INPUT') {
e.stopPropagation();
return;
}
clearTimeout($(this).data('tmlongtap'));
if (e.type == 'touchmove') {
$(this).removeClass(hover);
}
})
// toggle subfolders in tree
.on('click', selNavdir+'.'+collapsed+' .'+arrow, function(e) {
var arrow = $(this),
link = arrow.parent(selNavdir),
stree = link.next('.'+subtree),
dfrd = $.Deferred(),
slideTH = 30, cnt;
e.stopPropagation();
if (link.hasClass(loaded)) {
link.toggleClass(expanded);
fm.lazy(function() {
cnt = link.hasClass(expanded)? stree.children().length + stree.find('div.elfinder-navbar-subtree[style*=block]').children().length : stree.find('div:visible').length;
if (cnt > slideTH) {
stree.toggle();
fm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
checkSubdirs();
} else {
stree.stop(true, true)[link.hasClass(expanded)? 'slideDown' : 'slideUp'](opts.durations.slideUpDown, function(){
fm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
checkSubdirs();
});
}
}).always(function() {
dfrd.resolve();
});
} else {
spinner.insertBefore(arrow);
link.removeClass(collapsed);
fm.request({cmd : 'tree', target : fm.navId2Hash(link.attr('id'))})
.done(function(data) {
updateTree(Object.assign([], filter(data.tree)));
if (stree.children().length) {
link.addClass(collapsed+' '+expanded);
if (stree.children().length > slideTH) {
stree.show();
fm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
checkSubdirs();
} else {
stree.stop(true, true).slideDown(opts.durations.slideUpDown, function(){
fm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
checkSubdirs();
});
}
}
})
.always(function(data) {
spinner.remove();
link.addClass(loaded);
fm.one('treedone', function() {
dfrd.resolve();
});
});
}
arrow.data('dfrd', dfrd);
})
.on('contextmenu', selNavdir, function(e) {
var self = $(this);
// now dirname editing
if (self.find('input:text').length) {
e.stopPropagation();
return;
}
e.preventDefault();
fm.trigger('contextmenu', {
'type' : 'navbar',
'targets' : [fm.navId2Hash($(this).attr('id'))],
'x' : e.pageX,
'y' : e.pageY
});
self.addClass('ui-state-hover');
fm.getUI('contextmenu').children().on('mouseenter', function() {
self.addClass('ui-state-hover');
});
fm.bind('closecontextmenu', function() {
self.removeClass('ui-state-hover');
});
})
.on('scrolltoview', selNavdir, function(e, data) {
var self = $(this);
autoScroll(self.attr('id')).done(function() {
if (!data || data.blink === 'undefined' || data.blink) {
fm.resources.blink(self, 'lookme');
}
});
})
// prepend fake dir
.on('create.'+fm.namespace, function(e, item) {
var pdir = findSubtree(item.phash),
lock = item.move || false,
dir = $(itemhtml(item)).addClass('elfinder-navbar-wrapper-tmp'),
selected = fm.selected();
lock && selected.length && fm.trigger('lockfiles', {files: selected});
pdir.prepend(dir);
}),
scrolling = false,
navbarScrTm,
// move tree into navbar
navbar = fm.getUI('navbar').append(tree).show().on('scroll', function() {
scrolling = true;
navbarScrTm && cancelAnimationFrame(navbarScrTm);
navbarScrTm = requestAnimationFrame(function() {
scrolling = false;
checkSubdirs();
});
}),
prevSortTreeview = fm.sortAlsoTreeview;
fm.open(function(e) {
var data = e.data,
dirs = filter(data.files),
contextmenu = fm.getUI('contextmenu');
data.init && tree.empty();
if (fm.UA.iOS) {
navbar.removeClass('overflow-scrolling-touch').addClass('overflow-scrolling-touch');
}
if (dirs.length) {
fm.lazy(function() {
if (!contextmenu.data('cmdMaps')) {
contextmenu.data('cmdMaps', {});
}
updateTree(dirs);
updateArrows(dirs, loaded);
sync(dirs);
});
} else {
sync();
}
})
// add new dirs
.add(function(e) {
var dirs = filter(e.data.added);
if (dirs.length) {
updateTree(dirs);
updateArrows(dirs, collapsed);
}
})
// update changed dirs
.change(function(e) {
// do ot perfome while syncing
if (syncing) {
return;
}
var dirs = filter(e.data.changed, true),
length = dirs.length,
l = length,
tgts = $(),
changed = {},
dir, phash, node, tmp, realParent, reqParent, realSibling, reqSibling, isExpanded, isLoaded, parent, subdirs;
$.each(hasMoreDirs, function(h, node) {
node.trigger('update.'+fm.namespace, { change: 'prepare' });
});
while (l--) {
dir = dirs[l];
phash = dir.phash;
if ((node = $('#'+fm.navHash2Id(dir.hash))).length) {
parent = node.parent();
if (phash) {
realParent = node.closest('.'+subtree);
reqParent = findSubtree(phash);
realSibling = node.parent().next();
reqSibling = findSibling(reqParent, dir);
if (!reqParent.length) {
continue;
}
if (reqParent[0] !== realParent[0] || realSibling.get(0) !== reqSibling.get(0)) {
reqSibling.length ? reqSibling.before(parent) : reqParent.append(parent);
}
}
isExpanded = node.hasClass(expanded);
isLoaded = node.hasClass(loaded);
tmp = $(itemhtml(dir));
node.replaceWith(tmp.children(selNavdir));
! mobile && updateDroppable(null, parent);
if (dir.dirs
&& (isExpanded || isLoaded)
&& (node = $('#'+fm.navHash2Id(dir.hash)))
&& node.next('.'+subtree).children().length) {
isExpanded && node.addClass(expanded);
isLoaded && node.addClass(loaded);
}
subdirs |= dir.dirs == -1;
}
}
// to check subdirs
if (subdirs) {
checkSubdirs();
}
$.each(hasMoreDirs, function(h, node) {
node.trigger('update.'+fm.namespace, { change: 'done' });
});
length && sync(void(0), false);
})
// remove dirs
.remove(function(e) {
var dirs = e.data.removed,
l = dirs.length,
node, stree, removed;
$.each(hasMoreDirs, function(h, node) {
node.trigger('update.'+fm.namespace, { removed : dirs });
node.trigger('update.'+fm.namespace, { change: 'prepare' });
});
while (l--) {
if ((node = $('#'+fm.navHash2Id(dirs[l]))).length) {
removed = true;
stree = node.closest('.'+subtree);
node.parent().detach();
if (!stree.children().length) {
stree.hide().prev(selNavdir).removeClass(collapsed+' '+expanded+' '+loaded);
}
}
}
removed && fm.getUI('navbar').children('.ui-resizable-handle').trigger('resize');
$.each(hasMoreDirs, function(h, node) {
node.trigger('update.'+fm.namespace, { change: 'done' });
});
})
// lock/unlock dirs while moving
.bind('lockfiles unlockfiles', function(e) {
var lock = e.type == 'lockfiles',
helperLocked = e.data.helper? e.data.helper.data('locked') : false,
act = (lock && !helperLocked) ? 'disable' : 'enable',
dirs = $.grep(e.data.files||[], function(h) {
var dir = fm.file(h);
return dir && dir.mime == 'directory' ? true : false;
});
$.each(dirs, function(i, hash) {
var dir = $('#'+fm.navHash2Id(hash));
if (dir.length && !helperLocked) {
dir.hasClass(draggable) && dir.draggable(act);
dir.hasClass(droppable) && dir.droppable(act);
dir[lock ? 'addClass' : 'removeClass'](disabled);
}
});
})
.bind('sortchange', function() {
if (fm.sortAlsoTreeview || prevSortTreeview !== fm.sortAlsoTreeview) {
var dirs,
ends = [],
endsMap = {},
endsVid = {},
topVid = '',
single = false,
current;
fm.lazy(function() {
dirs = filter(fm.files());
prevSortTreeview = fm.sortAlsoTreeview;
tree.empty();
// append volume roots at first
updateTree($.map(fm.roots, function(h) {
var dir = fm.file(h);
return dir && !dir.phash? dir : null;
}));
if (!Object.keys(hasMoreDirs).length) {
updateTree(dirs);
current = selectPages();
updateArrows(dirs, loaded);
} else {
ends = getEnds();
if (ends.length > 1) {
$.each(ends, function(i, end) {
var vid = fm.file(fm.root(end)).volumeid;
if (i === 0) {
topVid = vid;
}
endsVid[vid] = end;
endsMap[end] = [];
});
$.each(dirs, function(i, d) {
if (!d.volumeid) {
single = true;
return false;
}
endsMap[endsVid[d.volumeid] || endsVid[topVid]].push(d);
});
} else {
single = true;
}
if (single) {
$.each(ends, function(i, endHash) {
updateTree(dirs);
current = selectPages(fm.file(endHash));
updateArrows(dirs, loaded);
});
} else {
$.each(endsMap, function(endHash, dirs) {
updateTree(dirs);
current = selectPages(fm.file(endHash));
updateArrows(dirs, loaded);
});
}
}
sync();
}, 100);
}
});
});
return this;
};
/*
* File: /js/ui/uploadButton.js
*/
/**
* @class elFinder toolbar's button tor upload file
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfinderuploadbutton = function(cmd) {
return this.each(function() {
var fm = cmd.fm,
button = $(this).elfinderbutton(cmd)
.off('click'),
form = $('<form/>').appendTo(button),
input = $('<input type="file" multiple="true" title="'+cmd.fm.i18n('selectForUpload')+'"/>')
.on('change', function() {
var _input = $(this);
if (_input.val()) {
fm.exec('upload', {input : _input.remove()[0]}, void(0), fm.cwd().hash);
input.clone(true).appendTo(form);
}
})
.on('dragover', function(e) {
e.originalEvent.dataTransfer.dropEffect = 'copy';
}),
tm;
form.append(input.clone(true));
cmd.change(function() {
tm && cancelAnimationFrame(tm);
tm = requestAnimationFrame(function() {
var toShow = cmd.disabled();
if (form.is('visible')) {
!toShow && form.hide();
} else {
toShow && form.show();
}
});
})
.change();
});
};
/*
* File: /js/ui/viewbutton.js
*/
/**
* @class elFinder toolbar button to switch current directory view.
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfinderviewbutton = function(cmd) {
return this.each(function() {
var button = $(this).elfinderbutton(cmd),
icon = button.children('.elfinder-button-icon'),
text = button.children('.elfinder-button-text'),
tm;
cmd.change(function() {
tm && cancelAnimationFrame(tm);
tm = requestAnimationFrame(function() {
var icons = cmd.value == 'icons';
icon.toggleClass('elfinder-button-icon-view-list', icons);
cmd.className = icons? 'view-list' : '';
cmd.title = cmd.fm.i18n(icons ? 'viewlist' : 'viewicons');
button.attr('title', cmd.title);
text.html(cmd.title);
});
});
});
};
/*
* File: /js/ui/workzone.js
*/
/**
* @class elfinderworkzone - elFinder container for nav and current directory
* @author Dmitry (dio) Levashov
**/
$.fn.elfinderworkzone = function(fm) {
var cl = 'elfinder-workzone';
this.not('.'+cl).each(function() {
var wz = $(this).addClass(cl),
prevH = Math.round(wz.height()),
parent = wz.parent(),
setDelta = function() {
wdelta = wz.outerHeight(true) - wz.height();
},
fitsize = function(e) {
var height = parent.height() - wdelta,
style = parent.attr('style'),
curH = Math.round(wz.height());
if (e) {
e.preventDefault();
e.stopPropagation();
}
parent.css('overflow', 'hidden')
.children(':visible:not(.'+cl+')').each(function() {
var ch = $(this);
if (ch.css('position') != 'absolute' && ch.css('position') != 'fixed') {
height -= ch.outerHeight(true);
}
});
parent.attr('style', style || '');
height = Math.max(0, Math.round(height));
if (prevH !== height || curH !== height) {
prevH = Math.round(wz.height());
wz.height(height);
fm.trigger('wzresize');
}
},
cssloaded = function() {
wdelta = wz.outerHeight(true) - wz.height();
fitsize();
},
wdelta;
setDelta();
parent.on('resize.' + fm.namespace, fitsize);
fm.one('cssloaded', cssloaded)
.bind('uiresize', fitsize)
.bind('themechange', setDelta);
});
return this;
};
/*
* File: /js/commands/archive.js
*/
/**
* @class elFinder command "archive"
* Archive selected files
*
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.commands.archive = function() {
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 && ! $.grep(sel, function(f){ return f.read ? false : true; }).length),
cwdId;
if (chk && fm.searchStatus.state > 1) {
cwdId = fm.cwd().volumeid;
chk = (cnt === $.grep(sel, function(f) { return f.read && f.hash.indexOf(cwdId) === 0 ? true : false; }).length);
}
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;
};
};
/*
* File: /js/commands/back.js
*/
/**
* @class elFinder command "back"
* Open last visited folder
*
* @author Dmitry (dio) Levashov
**/
(elFinder.prototype.commands.back = function() {
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
/*
* File: /js/commands/chmod.js
*/
/**
* @class elFinder command "chmod".
* Chmod files.
*
* @type elFinder.command
* @author Naoki Sawada
*/
elFinder.prototype.commands.chmod = function() {
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"/>{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;
if (!cnt) return false;
var chk = $.grep(sel, function(f) {
return (f.isowner && f.perm && isPerm(f.perm) && (cnt == 1 || f.mime != 'directory')) ? true : false;
}).length;
return (cnt == chk)? 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;
};
};
/*
* File: /js/commands/colwidth.js
*/
/**
* @class elFinder command "colwidth"
* CWD list table columns width to auto
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.colwidth = function() {
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();
};
};
/*
* File: /js/commands/copy.js
*/
/**
* @class elFinder command "copy".
* Put files in filemanager clipboard.
*
* @type elFinder.command
* @author Dmitry (dio) Levashov
*/
elFinder.prototype.commands.copy = function() {
this.shortcuts = [{
pattern : 'ctrl+c ctrl+insert'
}];
this.getstate = function(select) {
var sel = this.files(select),
cnt = sel.length;
return cnt && $.grep(sel, function(f) { return f.read ? true : false; }).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)));
};
};
/*
* File: /js/commands/cut.js
*/
/**
* @class elFinder command "copy".
* Put files in filemanager clipboard.
*
* @type elFinder.command
* @author Dmitry (dio) Levashov
*/
elFinder.prototype.commands.cut = function() {
var fm = this.fm;
this.shortcuts = [{
pattern : 'ctrl+x shift+insert'
}];
this.getstate = function(select) {
var sel = this.files(select),
cnt = sel.length;
return cnt && $.grep(sel, function(f) { return f.read && ! f.locked && ! fm.isRoot(f) ? true : false; }).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));
};
};
/*
* File: /js/commands/download.js
*/
/**
* @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() {
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.cwdHash2Id(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.cwdHash2Id(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/>')
.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"/>';
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/>')
.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.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());
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 && (!fm.UA.Safari || fm.isSameOrigin(fm.options.url))) || 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);
dllink = $('<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();
}
} else {
form = $('<form action="'+fm.options.url+'" method="post" target="'+uniq+'" style="display:none"/>')
.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);
}
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;
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 = [];
for (i = 0; i < files.length; i++) {
url = fm.openUrl(files[i].hash, true);
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 && (!fm.UA.Safari || fm.isSameOrigin(url))) {
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+'"/>';
}
}
}
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});
return dfrd.resolve();
}
};
};
/*
* File: /js/commands/duplicate.js
*/
/**
* @class elFinder command "duplicate"
* Create file/folder copy with suffix "copy Number"
*
* @type elFinder.command
* @author Dmitry (dio) Levashov
*/
elFinder.prototype.commands.duplicate = function() {
var fm = this.fm;
this.getstate = function(select) {
var sel = this.files(select),
cnt = sel.length;
return cnt && fm.cwd().write && $.grep(sel, function(f) { return f.read && f.phash === fm.cwd().hash && ! fm.isRoot(f)? true : false; }).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: /js/commands/edit.js
*/
/**
* @class elFinder command "edit".
* Edit text file in dialog window
*
* @author Dmitry (dio) Levashov, dio@std42.ru
**/
elFinder.prototype.commands.edit = function() {
var self = this,
fm = this.fm,
clsEditing = fm.res('class', 'editing'),
mimesSingle = [],
mimes = [],
allowAll = false,
rtrim = function(str){
return str.replace(/\s+$/, '');
},
getEncSelect = function(heads) {
var sel = $('<select class="ui-corner-all"/>'),
hval;
if (heads) {
$.each(heads, function(i, head) {
hval = fm.escape(head.value);
sel.append('<option value="'+hval+'">'+(head.caption? fm.escape(head.caption) : hval)+'</option>');
});
}
$.each(self.options.encodings, function(i, v) {
sel.append('<option value="'+v+'">'+v+'</option>');
});
return sel;
},
getDlgWidth = function() {
var m, width;
if (typeof self.options.dialogWidth === 'string' && (m = self.options.dialogWidth.match(/(\d+)%/))) {
width = parseInt(fm.getUI().width() * (m[1] / 100));
} else {
width = parseInt(self.options.dialogWidth || 650);
}
return Math.min(width, $(window).width());
},
/**
* Return files acceptable to edit
*
* @param Array files hashes
* @return Array
**/
filter = function(files) {
var cnt = files.length,
mime, ext, skip;
if (cnt > 1) {
mime = files[0].mime;
ext = files[0].name.replace(/^.*(\.[^.]+)$/, '$1');
}
return $.grep(files, function(file) {
var res;
if (skip || file.mime === 'directory') {
return false;
}
res = file.read
&& (allowAll || fm.mimeIsText(file.mime) || $.inArray(file.mime, cnt === 1? mimesSingle : mimes) !== -1)
&& (!self.onlyMimes.length || $.inArray(file.mime, self.onlyMimes) !== -1)
&& (cnt === 1 || (file.mime === mime && file.name.substr(ext.length * -1) === ext))
&& (fm.uploadMimeCheck(file.mime, file.phash)? true : false)
&& setEditors(file, cnt)
&& Object.keys(editors).length;
if (!res) {
skip = true;
}
return res;
});
},
fileSync = function(hash) {
var old = fm.file(hash),
f;
fm.request({
cmd: 'info',
targets: [hash],
preventDefault: true
}).done(function(data) {
var changed;
if (data && data.files && data.files.length) {
f = data.files[0];
if (old.ts != f.ts || old.size != f.size) {
changed = { changed: [ f ] };
fm.updateCache(changed);
fm.change(changed);
}
}
});
},
/**
* Open dialog with textarea to edit file
*
* @param String id dialog id
* @param Object file file object
* @param String content file content
* @return $.Deferred
**/
dialog = function(id, file, content, encoding, editor) {
var dfrd = $.Deferred(),
_loaded = false,
loaded = function() {
if (!_loaded) {
fm.toast({
mode: 'warning',
msg: fm.i18n('nowLoading')
});
return false;
}
return true;
},
save = function() {
var encord = selEncoding? selEncoding.val():void(0),
saveDfd = $.Deferred().fail(function(err) {
dialogNode.show().find('button.elfinder-btncnt-0,button.elfinder-btncnt-1').hide();
}),
conf, res;
if (!loaded()) {
return saveDfd.resolve();
}
if (ta.editor) {
ta.editor.save(ta[0], ta.editor.instance);
conf = ta.editor.confObj;
if (conf.info && (conf.info.schemeContent || conf.info.arrayBufferContent)) {
encord = 'scheme';
}
}
res = getContent();
setOld(res);
if (res.promise) {
res.done(function(data) {
dfrd.notifyWith(ta, [encord, ta.data('hash'), old, saveDfd]);
}).fail(function(err) {
saveDfd.reject(err);
});
} else {
dfrd.notifyWith(ta, [encord, ta.data('hash'), old, saveDfd]);
}
return saveDfd;
},
saveon = function() {
if (!loaded()) { return; }
save().fail(function(err) {
err && fm.error(err);
});
},
cancel = function() {
ta.elfinderdialog('close');
},
savecl = function() {
if (!loaded()) { return; }
save().done(function() {
_loaded = false;
dialogNode.show();
cancel();
}).fail(function(err) {
dialogNode.show();
err && fm.error(err);
});
dialogNode.hide();
},
saveAs = function() {
if (!loaded()) { return; }
var prevOld = old,
phash = fm.file(file.phash)? file.phash : fm.cwd().hash,
fail = function(err) {
dialogs.addClass(clsEditing).fadeIn(function() {
err && fm.error(err);
});
old = prevOld;
fm.disable();
},
make = function() {
self.mime = saveAsFile.mime || file.mime;
self.prefix = (saveAsFile.name || file.name).replace(/ \d+(\.[^.]+)?$/, '$1');
self.requestCmd = 'mkfile';
self.nextAction = {};
self.data = {target : phash};
$.proxy(fm.res('mixin', 'make'), self)()
.done(function(data) {
if (data.added && data.added.length) {
ta.data('hash', data.added[0].hash);
save().done(function() {
_loaded = false;
dialogNode.show();
cancel();
dialogs.fadeIn();
}).fail(fail);
} else {
fail();
}
})
.progress(function(err) {
if (err && err === 'errUploadMime') {
ta.trigger('saveAsFail');
}
})
.fail(fail)
.always(function() {
delete self.mime;
delete self.prefix;
delete self.nextAction;
delete self.data;
});
fm.trigger('unselectfiles', { files: [ file.hash ] });
},
reqOpen = null,
dialogs = fm.getUI().children('.' + self.dialogClass + ':visible');
if (dialogNode.is(':hidden')) {
dialogs = dialogs.add(dialogNode);
}
dialogs.removeClass(clsEditing).fadeOut();
fm.enable();
if (fm.searchStatus.state < 2 && phash !== fm.cwd().hash) {
reqOpen = fm.exec('open', [phash], {thash: phash});
}
$.when([reqOpen]).done(function() {
reqOpen? fm.one('cwdrender', make) : make();
}).fail(fail);
},
changed = function() {
var dfd = $.Deferred(),
res, tm;
if (!_loaded) {
return dfd.resolve(false);
}
ta.editor && ta.editor.save(ta[0], ta.editor.instance);
res = getContent();
if (res && res.promise) {
tm = setTimeout(function() {
fm.notify({
type : 'chkcontent',
cnt : 1,
hideCnt: true
});
}, 100);
res.always(function() {
tm && clearTimeout(tm);
fm.notify({ type : 'chkcontent', cnt: -1 });
}).done(function(d) {
dfd.resolve(old !== d);
}).fail(function(err) {
dfd.resolve(err || true);
});
} else {
dfd.resolve(old !== res);
}
return dfd;
},
opts = {
title : fm.escape(file.name),
width : getDlgWidth(),
buttons : {},
cssClass : clsEditing,
maxWidth : 'window',
maxHeight : 'window',
allowMinimize : true,
allowMaximize : true,
openMaximized : editorMaximized() || (editor && editor.info && editor.info.openMaximized),
btnHoverFocus : false,
closeOnEscape : false,
propagationEvents : ['mousemove', 'mouseup', 'click'],
minimize : function() {
var conf;
if (ta.editor && dialogNode.closest('.ui-dialog').is(':hidden')) {
conf = ta.editor.confObj;
if (conf.info && conf.info.syncInterval) {
fileSync(file.hash);
}
}
},
close : function() {
var close = function() {
var conf;
dfrd.resolve();
if (ta.editor) {
ta.editor.close(ta[0], ta.editor.instance);
conf = ta.editor.confObj;
if (conf.info && conf.info.syncInterval) {
fileSync(file.hash);
}
}
ta.elfinderdialog('destroy');
},
onlySaveAs = (typeof saveAsFile.name !== 'undefined'),
accept = onlySaveAs? {
label : 'btnSaveAs',
callback : function() {
requestAnimationFrame(saveAs);
}
} : {
label : 'btnSaveClose',
callback : function() {
save().done(function() {
close();
});
}
};
changed().done(function(change) {
var msgs = ['confirmNotSave'];
if (change) {
if (typeof change === 'string') {
msgs.unshift(change);
}
fm.confirm({
title : self.title,
text : msgs,
accept : accept,
cancel : {
label : 'btnClose',
callback : close
},
buttons : onlySaveAs? null : [{
label : 'btnSaveAs',
callback : function() {
requestAnimationFrame(saveAs);
}
}]
});
} else {
close();
}
});
},
open : function() {
var loadRes, conf, interval;
ta.initEditArea.call(ta, id, file, content, fm);
if (ta.editor) {
loadRes = ta.editor.load(ta[0]) || null;
if (loadRes && loadRes.done) {
loadRes.always(function() {
_loaded = true;
}).done(function(instance) {
ta.editor.instance = instance;
ta.editor.focus(ta[0], ta.editor.instance);
setOld(getContent());
requestAnimationFrame(function() {
dialogNode.trigger('resize');
});
}).fail(function(error) {
error && fm.error(error);
ta.elfinderdialog('destroy');
return;
});
} else {
_loaded = true;
if (loadRes && (typeof loadRes === 'string' || Array.isArray(loadRes))) {
fm.error(loadRes);
ta.elfinderdialog('destroy');
return;
}
ta.editor.instance = loadRes;
ta.editor.focus(ta[0], ta.editor.instance);
setOld(getContent());
requestAnimationFrame(function() {
dialogNode.trigger('resize');
});
}
conf = ta.editor.confObj;
if (conf.info && conf.info.syncInterval) {
if (interval = parseInt(conf.info.syncInterval)) {
setTimeout(function() {
autoSync(interval);
}, interval);
}
}
} else {
_loaded = true;
setOld(getContent());
}
},
resize : function(e, data) {
ta.editor && ta.editor.resize(ta[0], ta.editor.instance, e, data || {});
}
},
getContent = function() {
return ta.getContent.call(ta, ta[0]);
},
setOld = function(res) {
if (res && res.promise) {
res.done(function(d) {
old = d;
});
} else {
old = res;
}
},
autoSync = function(interval) {
if (dialogNode.is(':visible')) {
fileSync(file.hash);
setTimeout(function() {
autoSync(interval);
}, interval);
}
},
saveAsFile = {},
ta, old, dialogNode, selEncoding, extEditor, maxW, syncInterval;
if (editor) {
if (editor.html) {
ta = $(editor.html);
}
extEditor = {
init : editor.init || null,
load : editor.load,
getContent : editor.getContent || null,
save : editor.save,
beforeclose : typeof editor.beforeclose == 'function' ? editor.beforeclose : void 0,
close : typeof editor.close == 'function' ? editor.close : function() {},
focus : typeof editor.focus == 'function' ? editor.focus : function() {},
resize : typeof editor.resize == 'function' ? editor.resize : function() {},
instance : null,
doSave : saveon,
doCancel : cancel,
doClose : savecl,
file : file,
fm : fm,
confObj : editor,
trigger : function(evName, data) {
fm.trigger('editEditor' + evName, Object.assign({}, editor.info || {}, data));
}
};
}
if (!ta) {
if (!fm.mimeIsText(file.mime)) {
return dfrd.reject('errEditorNotFound');
}
(function() {
var stateChange = function() {
if (selEncoding) {
changed().done(function(change) {
if (change) {
selEncoding.attr('title', fm.i18n('saveAsEncoding')).addClass('elfinder-edit-changed');
} else {
selEncoding.attr('title', fm.i18n('openAsEncoding')).removeClass('elfinder-edit-changed');
}
});
}
};
ta = $('<textarea class="elfinder-file-edit" rows="20" id="'+id+'-ta"></textarea>')
.on('input propertychange', stateChange);
if (!ta.editor || !ta.editor.info || ta.editor.info.useTextAreaEvent) {
ta.on('keydown', function(e) {
var code = e.keyCode,
value, start;
e.stopPropagation();
if (code == $.ui.keyCode.TAB) {
e.preventDefault();
// insert tab on tab press
if (this.setSelectionRange) {
value = this.value;
start = this.selectionStart;
this.value = value.substr(0, start) + "\t" + value.substr(this.selectionEnd);
start += 1;
this.setSelectionRange(start, start);
}
}
if (e.ctrlKey || e.metaKey) {
// close on ctrl+w/q
if (code == 'Q'.charCodeAt(0) || code == 'W'.charCodeAt(0)) {
e.preventDefault();
cancel();
}
if (code == 'S'.charCodeAt(0)) {
e.preventDefault();
saveon();
}
}
})
.on('mouseenter', function(){this.focus();});
}
ta.initEditArea = function(id, file, content) {
var heads = (encoding && encoding !== 'unknown')? [{value: encoding}] : [],
wfake = $('<select/>').hide(),
setSelW = function(init) {
init && wfake.appendTo(selEncoding.parent());
wfake.empty().append($('<option/>').text(selEncoding.val()));
selEncoding.width(wfake.width());
};
// ta.hide() for performance tune. Need ta.show() in `load()` if use textarea node.
ta.hide().val(content);
if (content === '' || ! encoding || encoding !== 'UTF-8') {
heads.push({value: 'UTF-8'});
}
selEncoding = getEncSelect(heads).on('touchstart', function(e) {
// for touch punch event handler
e.stopPropagation();
}).on('change', function() {
// reload to change encoding if not edited
changed().done(function(change) {
if (! change && getContent() !== '') {
cancel();
edit(file, selEncoding.val(), editor).fail(function(err) { err && fm.error(err); });
}
});
setSelW();
}).on('mouseover', stateChange);
ta.parent().next().prepend($('<div class="ui-dialog-buttonset elfinder-edit-extras"/>').append(selEncoding));
setSelW(true);
};
})();
}
ta.data('hash', file.hash);
if (extEditor) {
ta.editor = extEditor;
if (typeof extEditor.beforeclose === 'function') {
opts.beforeclose = function() {
return extEditor.beforeclose(ta[0], extEditor.instance);
};
}
if (typeof extEditor.init === 'function') {
ta.initEditArea = extEditor.init;
}
if (typeof extEditor.getContent === 'function') {
ta.getContent = extEditor.getContent;
}
}
if (! ta.initEditArea) {
ta.initEditArea = function() {};
}
if (! ta.getContent) {
ta.getContent = function() {
return rtrim(ta.val());
};
}
if (!editor || !editor.info || !editor.info.preventGet) {
opts.buttons[fm.i18n('btnSave')] = saveon;
opts.buttons[fm.i18n('btnSaveClose')] = savecl;
opts.buttons[fm.i18n('btnSaveAs')] = saveAs;
opts.buttons[fm.i18n('btnCancel')] = cancel;
}
if (editor && typeof editor.prepare === 'function') {
editor.prepare(ta, opts, file);
}
dialogNode = self.fmDialog(ta, opts)
.attr('id', id)
.on('keydown keyup keypress', function(e) {
e.stopPropagation();
})
.css({ overflow: 'hidden', minHeight: '7em' })
.addClass('elfinder-edit-editor')
.closest('.ui-dialog')
.on('changeType', function(e, data) {
if (data.extention && data.mime) {
var ext = data.extention,
mime = data.mime,
btnSet = $(this).children('.ui-dialog-buttonpane').children('.ui-dialog-buttonset');
btnSet.children('.elfinder-btncnt-0,.elfinder-btncnt-1').hide();
saveAsFile.name = fm.splitFileExtention(file.name)[0] + '.' + data.extention;
saveAsFile.mime = data.mime;
if (!data.keepEditor) {
btnSet.children('.elfinder-btncnt-2').trigger('click');
}
}
});
// care to viewport scale change with mobile devices
maxW = (fm.options.dialogContained? elfNode : $(window)).width();
(dialogNode.width() > maxW) && dialogNode.width(maxW);
return dfrd.promise();
},
/**
* Get file content and
* open dialog with textarea to edit file content
*
* @param String file hash
* @return jQuery.Deferred
**/
edit = function(file, convert, editor) {
var hash = file.hash,
opts = fm.options,
dfrd = $.Deferred(),
id = 'edit-'+fm.namespace+'-'+file.hash,
d = fm.getUI().find('#'+id),
conv = !convert? 0 : convert,
req, error, res;
if (d.length) {
d.elfinderdialog('toTop');
return dfrd.resolve();
}
if (!file.read || (!file.write && (!editor.info || !editor.info.converter))) {
error = ['errOpen', file.name, 'errPerm'];
return dfrd.reject(error);
}
if (editor && editor.info) {
if (typeof editor.info.edit === 'function') {
res = editor.info.edit.call(fm, file, editor);
if (res.promise) {
res.done(function() {
dfrd.resolve();
}).fail(function(error) {
dfrd.reject(error);
});
} else {
res? dfrd.resolve() : dfrd.reject();
}
return dfrd;
}
if (editor.info.urlAsContent || editor.info.preventGet) {
req = $.Deferred();
if (! editor.info.preventGet) {
fm.url(hash, { async: true, temporary: true }).done(function(url) {
req.resolve({content: url});
});
} else {
req.resolve({});
}
} else {
req = fm.request({
data : {cmd : 'get', target : hash, conv : conv, _t : file.ts},
options : {type: 'get', cache : true},
notify : {type : 'file', cnt : 1},
preventDefault : true
});
}
req.done(function(data) {
var selEncoding, reg, m, res;
if (data.doconv) {
fm.confirm({
title : self.title,
text : data.doconv === 'unknown'? 'confirmNonUTF8' : 'confirmConvUTF8',
accept : {
label : 'btnConv',
callback : function() {
dfrd = edit(file, selEncoding.val(), editor);
}
},
cancel : {
label : 'btnCancel',
callback : function() { dfrd.reject(); }
},
optionsCallback : function(options) {
options.create = function() {
var base = $('<div class="elfinder-dialog-confirm-encoding"/>'),
head = {value: data.doconv},
detected;
if (data.doconv === 'unknown') {
head.caption = '-';
}
selEncoding = getEncSelect([head]);
$(this).next().find('.ui-dialog-buttonset')
.prepend(base.append($('<label>'+fm.i18n('encoding')+' </label>').append(selEncoding)));
};
}
});
} else {
if ((!editor || !editor.info || !editor.info.preventGet) && fm.mimeIsText(file.mime)) {
reg = new RegExp('^(data:'+file.mime.replace(/([.+])/g, '\\$1')+';base64,)', 'i');
if (!editor.info.dataScheme) {
if (window.atob && (m = data.content.match(reg))) {
data.content = atob(data.content.substr(m[1].length));
}
} else {
if (window.btoa && !data.content.match(reg)) {
data.content = 'data:'+file.mime+';base64,'+btoa(data.content);
}
}
}
dialog(id, file, data.content, data.encoding, editor)
.done(function(data) {
dfrd.resolve(data);
})
.progress(function(encoding, newHash, data, saveDfd) {
var ta = this;
if (newHash) {
hash = newHash;
}
fm.request({
options : {type : 'post'},
data : {
cmd : 'put',
target : hash,
encoding : encoding || data.encoding,
content : data
},
notify : {type : 'save', cnt : 1},
syncOnFail : true,
preventFail : true,
navigate : {
target : 'changed',
toast : {
inbuffer : {msg: fm.i18n(['complete', fm.i18n('btnSave')])}
}
}
})
.fail(function(error) {
dfrd.reject(error);
saveDfd.reject();
})
.done(function(data) {
requestAnimationFrame(function(){
ta.trigger('focus');
ta.editor && ta.editor.focus(ta[0], ta.editor.instance);
});
saveDfd.resolve();
});
})
.fail(function(error) {
dfrd.reject(error);
});
}
})
.fail(function(error) {
var err = fm.parseError(error);
err = Array.isArray(err)? err[0] : err;
(err !== 'errConvUTF8') && fm.sync();
dfrd.reject(error);
});
}
return dfrd.promise();
},
/**
* Current editors of selected files
*
* @type Object
*/
editors = {},
/**
* Fallback editor (Simple text editor)
*
* @type Object
*/
fallbackEditor = {
// Simple Text (basic textarea editor)
info : {
id : 'textarea',
name : 'TextArea',
useTextAreaEvent : true
},
load : function(textarea) {
// trigger event 'editEditorPrepare'
this.trigger('Prepare', {
node: textarea,
editorObj: void(0),
instance: void(0),
opts: {}
});
textarea.setSelectionRange && textarea.setSelectionRange(0, 0);
$(textarea).trigger('focus').show();
},
save : function(){}
},
/**
* Set current editors
*
* @param Object file object
* @param Number cnt count of selected items
* @return Void
*/
setEditors = function(file, cnt) {
var mimeMatch = function(fileMime, editorMimes){
if (!editorMimes) {
return fm.mimeIsText(fileMime);
} else {
if (editorMimes[0] === '*' || $.inArray(fileMime, editorMimes) !== -1) {
return true;
}
var i, l;
l = editorMimes.length;
for (i = 0; i < l; i++) {
if (fileMime.indexOf(editorMimes[i]) === 0) {
return true;
}
}
return false;
}
},
extMatch = function(fileName, editorExts){
if (!editorExts || !editorExts.length) {
return true;
}
var ext = fileName.replace(/^.+\.([^.]+)|(.+)$/, '$1$2').toLowerCase(),
i, l;
l = editorExts.length;
for (i = 0; i < l; i++) {
if (ext === editorExts[i].toLowerCase()) {
return true;
}
}
return false;
},
optEditors = self.options.editors || [],
cwdWrite = fm.cwd().write;
stored = fm.storage('storedEditors') || {};
editors = {};
if (!optEditors.length) {
optEditors = [fallbackEditor];
}
$.each(optEditors, function(i, editor) {
var name;
if ((cnt === 1 || !editor.info.single)
&& ((!editor.info || !editor.info.converter)? file.write : cwdWrite)
&& (file.size > 0 || (!editor.info.converter && (editor.info.canMakeEmpty || (editor.info.canMakeEmpty !== false && fm.mimeIsText(file.mime)))))
&& (!editor.info.maxSize || file.size <= editor.info.maxSize)
&& mimeMatch(file.mime, editor.mimes || null)
&& extMatch(file.name, editor.exts || null)
&& typeof editor.load == 'function'
&& typeof editor.save == 'function') {
name = editor.info.name? editor.info.name : ('Editor ' + i);
editor.id = editor.info.id? editor.info.id : ('editor' + i),
editor.name = name;
editor.i18n = fm.i18n(name);
editors[editor.id] = editor;
}
});
return Object.keys(editors).length? true : false;
},
store = function(mime, editor) {
if (mime && editor) {
if (!$.isPlainObject(stored)) {
stored = {};
}
stored[mime] = editor.id;
fm.storage('storedEditors', stored);
fm.trigger('selectfiles', {files : fm.selected()});
}
},
useStoredEditor = function() {
var d = fm.storage('useStoredEditor');
return d? (d > 0) : self.options.useStoredEditor;
},
editorMaximized = function() {
var d = fm.storage('editorMaximized');
return d? (d > 0) : self.options.editorMaximized;
},
getSubMenuRaw = function(files, callback) {
var subMenuRaw = [];
$.each(editors, function(id, ed) {
subMenuRaw.push(
{
label : fm.escape(ed.i18n),
icon : ed.info && ed.info.icon? ed.info.icon : 'edit',
options : { iconImg: ed.info && ed.info.iconImg? fm.baseUrl + ed.info.iconImg : void(0) },
callback : function() {
store(files[0].mime, ed);
callback && callback.call(ed);
}
}
);
});
return subMenuRaw;
},
getStoreId = function(name) {
// for compatibility to previous version
return name.toLowerCase().replace(/ +/g, '');
},
getStoredEditor = function(mime) {
var name = stored[mime];
return name && Object.keys(editors).length? editors[getStoreId(name)] : void(0);
},
infoRequest = function() {
},
stored;
this.shortcuts = [{
pattern : 'ctrl+e'
}];
this.init = function() {
var self = this,
fm = this.fm,
opts = this.options,
cmdChecks = [],
ccData, dfd;
this.onlyMimes = this.options.mimes || [];
fm.one('open', function() {
// editors setup
if (opts.editors && Array.isArray(opts.editors)) {
fm.trigger('canMakeEmptyFile', {mimes: Object.keys(fm.storage('mkfileTextMimes') || {}).concat(opts.makeTextMimes || ['text/plain'])});
$.each(opts.editors, function(i, editor) {
if (editor.info && editor.info.cmdCheck) {
cmdChecks.push(editor.info.cmdCheck);
}
});
if (cmdChecks.length) {
if (fm.api >= 2.1030) {
dfd = fm.request({
data : {
cmd: 'editor',
name: cmdChecks,
method: 'enabled'
},
preventDefault : true
}).done(function(d) {
ccData = d;
}).fail(function() {
ccData = {};
});
} else {
ccData = {};
dfd = $.Deferred().resolve();
}
} else {
dfd = $.Deferred().resolve();
}
dfd.always(function() {
if (ccData) {
opts.editors = $.grep(opts.editors, function(e) {
if (e.info && e.info.cmdCheck) {
return ccData[e.info.cmdCheck]? true : false;
} else {
return true;
}
});
}
$.each(opts.editors, function(i, editor) {
if (editor.setup && typeof editor.setup === 'function') {
editor.setup.call(editor, opts, fm);
}
if (!editor.disabled) {
if (editor.mimes && Array.isArray(editor.mimes)) {
mimesSingle = mimesSingle.concat(editor.mimes);
if (!editor.info || !editor.info.single) {
mimes = mimes.concat(editor.mimes);
}
}
if (!allowAll && editor.mimes && editor.mimes[0] === '*') {
allowAll = true;
}
if (!editor.info) {
editor.info = {};
}
if (editor.info.integrate) {
fm.trigger('helpIntegration', Object.assign({cmd: 'edit'}, editor.info.integrate));
}
if (editor.info.canMakeEmpty) {
fm.trigger('canMakeEmptyFile', {mimes: editor.mimes});
}
}
});
mimesSingle = ($.uniqueSort || $.unique)(mimesSingle);
mimes = ($.uniqueSort || $.unique)(mimes);
opts.editors = $.grep(opts.editors, function(e) {
return e.disabled? false : true;
});
});
}
})
.bind('select', function() {
editors = null;
})
.bind('contextmenucreate', function(e) {
var file, editor,
single = function(editor) {
var title = self.title;
fm.one('contextmenucreatedone', function() {
self.title = title;
});
self.title = fm.escape(editor.i18n);
if (editor.info && editor.info.iconImg) {
self.contextmenuOpts = {
iconImg: fm.baseUrl + editor.info.iconImg
};
}
delete self.variants;
};
self.contextmenuOpts = void(0);
if (e.data.type === 'files' && self.enabled()) {
file = fm.file(e.data.targets[0]);
if (setEditors(file, e.data.targets.length)) {
if (Object.keys(editors).length > 1) {
if (!useStoredEditor() || !(editor = getStoredEditor(file.mime))) {
delete self.extra;
self.variants = [];
$.each(editors, function(id, editor) {
self.variants.push([{ editor: editor }, editor.i18n, editor.info && editor.info.iconImg? fm.baseUrl + editor.info.iconImg : 'edit']);
});
} else {
single(editor);
self.extra = {
icon: 'menu',
node: $('<span/>')
.attr({title: fm.i18n('select')})
.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(fm.selectedFiles(), function() {
var hashes = fm.selected();
fm.exec('edit', hashes, {editor: this});
fm.trigger('selectfiles', {files : hashes});
}),
x: node.offset().left,
y: node.offset().top
});
})
};
}
} else {
single(editors[Object.keys(editors)[0]]);
delete self.extra;
}
}
}
})
.bind('canMakeEmptyFile', function(e) {
if (e.data && e.data.resetTexts) {
var defs = fm.arrayFlip(self.options.makeTextMimes || ['text/plain']),
hides = fm.storage('mkfileHides') || {};
$.each((fm.storage('mkfileTextMimes') || {}), function(mime, type) {
if (!defs[mime]) {
delete fm.mimesCanMakeEmpty[mime];
delete hides[mime];
}
});
fm.storage('mkfileTextMimes', null);
if (Object.keys(hides).length) {
fm.storage('mkfileHides', hides);
} else {
fm.storage('mkfileHides', null);
}
}
});
};
this.getstate = function(select) {
var sel = this.files(select),
cnt = sel.length;
return cnt && filter(sel).length == cnt ? 0 : -1;
};
this.exec = function(select, opts) {
var fm = this.fm,
files = filter(this.files(select)),
hashes = $.map(files, function(f) { return f.hash; }),
list = [],
editor = opts && opts.editor? opts.editor : null,
node = $(opts && opts._currentNode? opts._currentNode : $('#'+ fm.cwdHash2Id(hashes[0]))),
getEditor = function() {
var dfd = $.Deferred(),
storedId;
if (!editor && Object.keys(editors).length > 1) {
if (useStoredEditor() && (editor = getStoredEditor(files[0].mime))) {
return dfd.resolve(editor);
}
fm.trigger('contextmenu', {
raw: getSubMenuRaw(files, function() {
dfd.resolve(this);
}),
x: node.offset().left,
y: node.offset().top + 22,
opened: function() {
fm.one('closecontextmenu',function() {
requestAnimationFrame(function() {
if (dfd.state() === 'pending') {
dfd.reject();
}
});
});
}
});
fm.trigger('selectfiles', {files : hashes});
return dfd;
} else {
Object.keys(editors).length > 1 && editor && store(files[0].mime, editor);
return dfd.resolve(editor? editor : (Object.keys(editors).length? editors[Object.keys(editors)[0]] : null));
}
},
dfrd = $.Deferred(),
file;
if (editors === null) {
setEditors(files[0], hashes.length);
}
if (!node.length) {
node = fm.getUI('cwd');
}
getEditor().done(function(editor) {
while ((file = files.shift())) {
list.push(edit(file, void(0), editor).fail(function(error) {
error && fm.error(error);
}));
}
if (list.length) {
$.when.apply(null, list).done(function() {
dfrd.resolve();
}).fail(function() {
dfrd.reject();
});
} else {
dfrd.reject();
}
}).fail(function() {
dfrd.reject();
});
return dfrd;
};
};
/*
* File: /js/commands/empty.js
*/
/**
* @class elFinder command "empty".
* Empty the folder
*
* @type elFinder.command
* @author Naoki Sawada
*/
elFinder.prototype.commands.empty = function() {
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;
cnt = sel.length;
return $.grep(sel, function(f) { return f.read && f.write && f.mime === 'directory' ? true : false; }).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;
};
};
/*
* File: /js/commands/extract.js
*/
/**
* @class elFinder command "extract"
* Extract files from archive
*
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.commands.extract = function() {
var self = this,
fm = self.fm,
mimes = [],
filter = function(files) {
return $.grep(files, function(file) {
return file.read && $.inArray(file.mime, mimes) !== -1 ? true : false;
});
};
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;
return cnt && this.fm.cwd().write && filter(sel).length == cnt ? 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;
var overwriteAll = false;
var omitAll = false;
var mkdirAll = 0;
var names = $.map(fm.files(hashes), function(file) { return file.name; });
var map = {};
$.grep(fm.files(hashes), function(file) {
map[file.name] = file;
return false;
});
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;
};
};
/*
* File: /js/commands/forward.js
*/
/**
* @class elFinder command "forward"
* Open next visited folder
*
* @author Dmitry (dio) Levashov
**/
(elFinder.prototype.commands.forward = function() {
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
/*
* File: /js/commands/fullscreen.js
*/
/**
* @class elFinder command "fullscreen"
* elFinder node to full scrren mode
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.fullscreen = function() {
var self = this,
fm = this.fm,
update = function(e, data) {
e.preventDefault();
e.stopPropagation();
if (data && data.fullscreen) {
self.update(void(0), (data.fullscreen === 'on'));
}
};
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);
});
};
/*
* File: /js/commands/getfile.js
*/
/**
* @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() {
var self = this,
fm = this.fm,
filter = function(files) {
var o = self.options;
files = $.grep(files, function(file) {
return (file.mime != 'directory' || o.folders) && file.read ? true : false;
});
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
/*
* File: /js/commands/help.js
*/
/**
* @class elFinder command "help"
* "About" dialog
*
* @author Dmitry (dio) Levashov
**/
(elFinder.prototype.commands.help = function() {
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"/>',
selfUrl = $('base').length? 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"/>');
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 &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-2018, Studio 42</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"/>');
},
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/>').text(k));
if (typeof v === 'undefined') {
elm.append($('<dd/>').append($('<span/>').text('undfined')));
} else if (typeof v === 'object' && !v) {
elm.append($('<dd/>').append($('<span/>').text('null')));
} else if (typeof v === 'object' && ($.isPlainObject(v) || v.length)) {
elm.append( $('<dd/>').append(render($('<dl/>'), v)));
} else {
elm.append($('<dd/>').append($('<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/>').html('<a href="'+selfUrl+'#'+tabId+'">'+self.debug.debug.cmd+'</a>').prependTo(debugUL);
target = $('<div id="'+tabId+'"/>').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/>').text('debug'), render($('<dl/>'), debug.debug));
target.append(info);
}
if (debug.options) {
info = $('<fieldset>').append($('<legend/>').text('options'), render($('<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"/>').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/>').attr('href', data.link).attr('target', '_blank').text(data.title);
} else {
elm = $('<span/>').text(data.title);
}
if (data.banner) {
elm = $('<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"/>').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.append($('<li/>').append($('<span/>').html(fm.i18n('cmd'+data.cmd))).append(cmdUL));
}
elm = cmdUL.append($('<li/>').append(elm));
} else {
ul.append($('<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
/*
* File: /js/commands/hidden.js
*/
/**
* @class elFinder command "hidden"
* Always hidden command for uiCmdMap
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.hidden = function() {
this.hidden = true;
this.updateOnSelect = false;
this.getstate = function() {
return -1;
};
};
/*
* File: /js/commands/hide.js
*/
/**
* @class elFinder command "hide".
* folders/files to hide as personal setting.
*
* @type elFinder.command
* @author Naoki Sawada
*/
elFinder.prototype.commands.hide = function() {
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 (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);
};
};
/*
* File: /js/commands/home.js
*/
(elFinder.prototype.commands.home = function() {
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
/*
* File: /js/commands/info.js
*/
/**
* @class elFinder command "info".
* Display dialog with file properties.
*
* @author Dmitry (dio) Levashov, dio@std42.ru
**/
(elFinder.prototype.commands.info = function() {
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}/>{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}"/>'
};
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',
size, tmb, file, title, dcnt, rdcnt, path, getHashAlgorisms, hideItems;
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 {
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)));
// Get MD5 hash
if (window.ArrayBuffer && (fm.options.cdns.sparkmd5 || fm.options.cdns.jssha) && file.mime !== 'directory' && file.size > 0 && (!o.showHashMaxsize || file.size <= o.showHashMaxsize)) {
getHashAlgorisms = [];
$.each(fm.storage('hashchekcer') || o.showHashAlgorisms, function(i, n) {
if (!file[n]) {
content.push(row.replace(l, fm.i18n(n)).replace(v, tpl.spinner.replace('{text}', msg.calc).replace('{name}', n)));
getHashAlgorisms.push(n);
} else {
content.push(row.replace(l, fm.i18n(n)).replace(v, file[n]).replace('{class}', hashClass));
}
});
reqs.push(
fm.getContentsHashes(file.hash, getHashAlgorisms).progress(function(hashes) {
$.each(getHashAlgorisms, function(i, n) {
if (hashes[n]) {
replSpinner(hashes[n], n, hashClass);
}
});
}).always(function() {
$.each(getHashAlgorisms, function(i, n) {
replSpinner(msg.unknown, n);
});
})
);
}
// 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 (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
/*
* File: /js/commands/mkdir.js
*/
/**
* @class elFinder command "mkdir"
* Create new folder
*
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.commands.mkdir = function() {
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;
if (curOrg === 'navbar') {
return cnt && sel[0].write && sel[0].read? 0 : -1;
} else {
return cwd.write && (!cnt || $.grep(sel, function(f) { return f.read && ! f.locked? true : false; }).length == cnt)? 0 : -1;
}
};
};
/*
* File: /js/commands/mkfile.js
*/
/**
* @class elFinder command "mkfile"
* Create new empty file
*
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.commands.mkfile = function() {
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.storage('mkfileHides') || {};
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);
};
};
/*
* File: /js/commands/netmount.js
*/
/**
* @class elFinder command "netmount"
* Mount network volume with user credentials.
*
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.commands.netmount = function() {
var self = this,
hasMenus = false,
content;
this.alwaysEnabled = true;
this.updateOnSelect = false;
this.drivers = [];
this.handlers = {
load : function() {
var fm = self.fm;
self.drivers = fm.netDrivers;
if (self.drivers.length) {
requestAnimationFrame(function() {
$.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/>')
.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);
}
requestAnimationFrame(function() {
content.find('input:text.elfinder-tabstop:visible:first').trigger('focus');
});
})
.addClass('ui-corner-all')
},
opts = {
title : fm.i18n('netMountDialogTitle'),
resizable : false,
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];
$.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}});
}
fm.request({data : data, notify : {type : 'netmount', cnt : 1, hideCnt : true}})
.done(function(data) {
var pdir;
if (data.added && data.added.length) {
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"/>').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/>'),
dialog;
content = $('<table class="elfinder-info-tb elfinder-netmount-tb"/>')
.append($('<tr/>').append($('<td>'+fm.i18n('protocol')+'</td>')).append($('<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/>').addClass('elfinder-netmount-tr elfinder-netmount-tr-'+protocol).append($('<td>'+fm.i18n(name)+'</td>')).append($('<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();
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);
dialogNode = dialog.closest('.ui-dialog');
dialog.ready(function(){
inputs.protocol.trigger('change');
dialog.elfinderdialog('posInit');
});
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;
if (d && d.protocol) {
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');
}
}
});
};
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;
};
};
/*
* File: /js/commands/open.js
*/
/**
* @class elFinder command "open"
* Enter folder or open files in new windows
*
* @author Dmitry (dio) Levashov
**/
(elFinder.prototype.commands.open = function() {
var fm = this.fm;
this.alwaysEnabled = true;
this.noChangeDirOnRemovedCwd = true;
this._handlers = {
dblclick : function(e) { e.preventDefault(); fm.exec('open', e.data && e.data.file? [ e.data.file ]: void(0)); },
'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;
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 wnd, target, getOnly;
try {
reg = new RegExp(fm.option('dispInlineRegex'), 'i');
} catch(e) {
reg = false;
}
// open files
link = $('<a>').hide().appendTo($('body')),
html5dl = (typeof link.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));
url = fm.openUrl(file.hash, !inline);
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();
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
/*
* File: /js/commands/opendir.js
*/
/**
* @class elFinder command "opendir"
* Enter parent folder
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.opendir = function() {
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;
};
};
/*
* File: /js/commands/opennew.js
*/
/**
* @class elFinder command "opennew"
* Open folder in new window
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.opennew = function() {
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();
}
};
};
/*
* File: /js/commands/paste.js
*/
/**
* @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() {
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},
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() {
dfrd.reject();
})
.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;
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;
}
$.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([]);
});
return dfrd;
};
};
/*
* File: /js/commands/places.js
*/
/**
* @class elFinder command "places"
* Regist to Places
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.places = function() {
var self = this,
fm = this.fm,
filter = function(hashes) {
return $.grep(self.files(hashes), function(f) { return f.mime == 'directory' ? true : false; });
},
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;
});
};
/*
* File: /js/commands/preference.js
*/
/**
* @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"/>'),
sep = '<div class="elfinder-preference-separator"/>',
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', 'showHidden'],
'dialog' : ['autoFocusDialog'],
'selectionInfo' : ['infoItems', 'hashChecker'],
'reset' : ['clearBrowserData'],
'all' : true
},
forms = self.options.prefs || ['language', 'theme', 'toolbarPref', 'iconSize', 'columnPref', 'selectAction', 'makefileTypes', 'useStoredEditor', 'editorMaximized', 'showHidden', 'infoItems', 'hashChecker', 'autoFocusDialog', 'clearBrowserData'];
forms = fm.arrayFlip(forms, true);
if (fm.options.getFileCallback) {
delete forms.selectAction;
}
forms.language && (forms.language = (function() {
var langSel = $('<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',
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: '正體中文'
};
$.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() {
if (!fm.options.themes || !Object.keys(fm.options.themes).length) {
return null;
}
var themeSel = $('<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"/>').text(fm.i18n('default')).on('click', function(e) {
themeSel.val('default').trigger('change');
}),
list = $('<div class="elfinder-reference-hide-taball"/>').on('click', 'button', function() {
var val = $(this).data('themeid')
themeSel.val(val).trigger('change');
});
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"/></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/>');
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"/>').append($('<button class="ui-button ui-corner-all ui-widget"/>').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/>').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') || 0,
sld = $('<div class="touch-punch"/>').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/>').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.storage('mkfileHides') || {},
getTag = function() {
var tags = [];
// re-assign hides
hides = fm.storage('mkfileHides') || {};
$.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/>').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/>').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"/>').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"/>').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/>').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);
}));
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"/>').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/>').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/>').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+'"/>').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"/>')
.hide()
.append($('<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();
};
};
/*
* File: /js/commands/quicklook.js
*/
/**
* @class elFinder command "quicklook"
* Fast preview for some files types
*
* @author Dmitry (dio) Levashov
**/
(elFinder.prototype.commands.quicklook = function() {
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,
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"/>'),
icon = $('<div/>'),
info = $('<div class="elfinder-quicklook-info"/>'),//.hide(),
cover = $('<div class="ui-front elfinder-quicklook-cover"/>'),
fsicon = $('<div class="'+navicon+' '+navicon+'-fullscreen"/>')
.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"/>').on('click touchstart', function(e) { ! navmove && navtrigger(leftKey); return false; }),
next = $('<div class="'+navicon+' '+navicon+'-next"/>').on('click touchstart', function(e) { ! navmove && navtrigger(rightKey); return false; }),
navbar = $('<div class="elfinder-quicklook-navbar"/>')
.append(prev)
.append(fsicon)
.append(next)
.append('<div class="elfinder-quicklook-navbar-separator"/>')
.append($('<div class="'+navicon+' '+navicon+'-close"/>').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"/>').on('mousedown', function(e) {
e.stopPropagation();
self.window.trigger('close');
}),
titleDock = $('<span class="ui-front ui-icon elfinder-icon-minimize ui-icon-minusthick"/>').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"/>',
navStyle = '',
init = true,
dockHeight, getSize, tm4cwd, dockedNode, selectTm;
this.cover = cover;
this.evUpdate = evUpdate;
(this.navbar = navbar)._show = navShow;
this.resize = 'resize.'+fm.namespace;
this.info = $('<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"/>')
// 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"/>')
.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"/>')
.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' : '')+'"/>').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.cwdHash2Id(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() { 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
/*
* File: /js/commands/quicklook.plugins.js
*/
elFinder.prototype.commands.quicklook.plugins = [
/**
* Images preview plugin
*
* @param elFinder.commands.quicklook
**/
function(ql) {
var mimes = ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/x-ms-bmp'],
preview = ql.preview,
WebP, flipMime;
// webp support
WebP = new Image();
WebP.onload = WebP.onerror = function() {
if (WebP.height == 2) {
mimes.push('image/webp');
}
};
WebP.src='data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
// what kind of images we can display
$.each(navigator.mimeTypes, function(i, o) {
var mime = o.type;
if (mime.indexOf('image/') === 0 && $.inArray(mime, mimes)) {
mimes.push(mime);
}
});
preview.on(ql.evUpdate, function(e) {
var fm = ql.fm,
file = e.file,
showed = false,
dimreq = null,
setdim = function(dim) {
var rfile = fm.file(file.hash);
rfile.width = dim[0];
rfile.height = dim[1];
},
show = function() {
var elm, varelm, memSize, width, height, prop;
dimreq && dimreq.state && dimreq.state() === 'pending' && dimreq.reject();
if (showed) {
return;
}
showed = true;
elm = img.get(0);
memSize = file.width && file.height? {w: file.width, h: file.height} : (elm.naturalWidth? null : {w: img.width(), h: img.height()});
memSize && img.removeAttr('width').removeAttr('height');
width = file.width || elm.naturalWidth || elm.width || img.width();
height = file.height || elm.naturalHeight || elm.height || img.height();
if (!file.width || !file.height) {
setdim([width, height]);
}
memSize && img.width(memSize.w).height(memSize.h);
prop = (width/height).toFixed(2);
preview.on('changesize', function() {
var pw = parseInt(preview.width()),
ph = parseInt(preview.height()),
w, h;
if (prop < (pw/ph).toFixed(2)) {
h = ph;
w = Math.floor(h * prop);
} else {
w = pw;
h = Math.floor(w/prop);
}
img.width(w).height(h).css('margin-top', h < ph ? Math.floor((ph - h)/2) : 0);
})
.trigger('changesize');
//show image
img.fadeIn(100);
},
hideInfo = function() {
loading.remove();
// hide info/icon
ql.hideinfo();
},
url, img, loading, m;
if (!flipMime) {
flipMime = fm.arrayFlip(mimes);
}
if (flipMime[file.mime] && ql.dispInlineRegex.test(file.mime)) {
// this is our file - stop event propagation
e.stopImmediatePropagation();
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"/></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
url = fm.openUrl(file.hash);
img = $('<img/>')
.hide()
.appendTo(preview)
.on('load', function() {
hideInfo();
show();
})
.on('error', function() {
loading.remove();
})
.attr('src', url);
if (file.width && file.height) {
show();
} else if (file.size > (ql.options.getDimThreshold || 0)) {
dimreq = fm.request({
data : {cmd : 'dim', target : file.hash},
preventDefault : true
})
.done(function(data) {
if (data.dim) {
var dim = data.dim.split('x');
file.width = dim[0];
file.height = dim[1];
setdim(dim);
show();
}
});
}
}
});
},
/**
* PSD(Adobe Photoshop data) preview plugin
*
* @param elFinder.commands.quicklook
**/
function(ql) {
var fm = ql.fm,
mimes = fm.arrayFlip(['image/vnd.adobe.photoshop', 'image/x-photoshop']),
preview = ql.preview,
load = function(url, img, loading) {
try {
fm.replaceXhrSend();
PSD.fromURL(url).then(function(psd) {
var prop;
img.attr('src', psd.image.toBase64());
requestAnimationFrame(function() {
prop = (img.width()/img.height()).toFixed(2);
preview.on('changesize', function() {
var pw = parseInt(preview.width()),
ph = parseInt(preview.height()),
w, h;
if (prop < (pw/ph).toFixed(2)) {
h = ph;
w = Math.floor(h * prop);
} else {
w = pw;
h = Math.floor(w/prop);
}
img.width(w).height(h).css('margin-top', h < ph ? Math.floor((ph - h)/2) : 0);
}).trigger('changesize');
loading.remove();
// hide info/icon
ql.hideinfo();
//show image
img.fadeIn(100);
});
}, function() {
loading.remove();
img.remove();
});
fm.restoreXhrSend();
} catch(e) {
fm.restoreXhrSend();
loading.remove();
img.remove();
}
},
PSD;
preview.on(ql.evUpdate, function(e) {
var file = e.file,
url, img, loading, m,
_define, _require;
if (mimes[file.mime] && fm.options.cdns.psd && ! fm.UA.ltIE10 && ql.dispInlineRegex.test(file.mime)) {
// this is our file - stop event propagation
e.stopImmediatePropagation();
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"/></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
url = fm.openUrl(file.hash);
if (!fm.isSameOrigin(url)) {
url = fm.openUrl(file.hash, true);
}
img = $('<img/>').hide().appendTo(preview);
if (PSD) {
load(url, img, loading);
} else {
_define = window.define;
_require = window.require;
window.require = null;
window.define = null;
fm.loadScript(
[ fm.options.cdns.psd ],
function() {
PSD = require('psd');
_define? (window.define = _define) : (delete window.define);
_require? (window.require = _require) : (delete window.require);
load(url, img, loading);
}
);
}
}
});
},
/**
* HTML preview plugin
*
* @param elFinder.commands.quicklook
**/
function(ql) {
var fm = ql.fm,
mimes = fm.arrayFlip(['text/html', 'application/xhtml+xml']),
preview = ql.preview;
preview.on(ql.evUpdate, function(e) {
var file = e.file, jqxhr, loading;
if (mimes[file.mime] && ql.dispInlineRegex.test(file.mime) && (!ql.options.getSizeMax || file.size <= ql.options.getSizeMax)) {
e.stopImmediatePropagation();
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"/></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
// stop loading on change file if not loaded yet
preview.one('change', function() {
jqxhr.state() == 'pending' && jqxhr.reject();
}).addClass('elfinder-overflow-auto');
jqxhr = fm.request({
data : {cmd : 'get', target : file.hash, conv : 1, _t : file.ts},
options : {type: 'get', cache : true},
preventDefault : true
})
.done(function(data) {
ql.hideinfo();
var doc = $('<iframe class="elfinder-quicklook-preview-html"/>').appendTo(preview)[0].contentWindow.document;
doc.open();
doc.write(data.content);
doc.close();
})
.always(function() {
loading.remove();
});
}
});
},
/**
* MarkDown preview plugin
*
* @param elFinder.commands.quicklook
**/
function(ql) {
var fm = ql.fm,
mimes = fm.arrayFlip(['text/x-markdown']),
preview = ql.preview,
marked = null,
show = function(data, loading) {
ql.hideinfo();
var doc = $('<iframe class="elfinder-quicklook-preview-html"/>').appendTo(preview)[0].contentWindow.document;
doc.open();
doc.write(marked(data.content));
doc.close();
loading.remove();
},
error = function(loading) {
marked = false;
loading.remove();
};
preview.on(ql.evUpdate, function(e) {
var file = e.file, jqxhr, loading;
if (mimes[file.mime] && fm.options.cdns.marked && marked !== false && ql.dispInlineRegex.test(file.mime) && (!ql.options.getSizeMax || file.size <= ql.options.getSizeMax)) {
e.stopImmediatePropagation();
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"/></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
// stop loading on change file if not loaded yet
preview.one('change', function() {
jqxhr.state() == 'pending' && jqxhr.reject();
}).addClass('elfinder-overflow-auto');
jqxhr = fm.request({
data : {cmd : 'get', target : file.hash, conv : 1, _t : file.ts},
options : {type: 'get', cache : true},
preventDefault : true
})
.done(function(data) {
if (marked || window.marked) {
if (!marked) {
marked = window.marked;
}
show(data, loading);
} else {
fm.loadScript([fm.options.cdns.marked],
function(res) {
marked = res || window.marked || false;
delete window.marked;
if (marked) {
show(data, loading);
} else {
error(loading);
}
},
{
tryRequire: true,
error: function() {
error(loading);
}
}
);
}
})
.fail(function() {
error(loading);
});
}
});
},
/**
* PDF/ODT/ODS/ODP preview with ViewerJS
*
* @param elFinder.commands.quicklook
*/
function(ql) {
if (ql.options.viewerjs) {
var fm = ql.fm,
preview = ql.preview,
opts = ql.options.viewerjs,
mimes = opts.url? fm.arrayFlip(opts.mimes || []) : [];
if (opts.url) {
preview.on('update', function(e) {
var win = ql.window,
file = e.file, node, loading;
if (mimes[file.mime]) {
var url = fm.openUrl(file.hash);
if (url && fm.isSameOrigin(url)) {
e.stopImmediatePropagation();
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"/></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
node = $('<iframe class="elfinder-quicklook-preview-iframe"/>')
.css('background-color', 'transparent')
.on('load', function() {
ql.hideinfo();
loading.remove();
node.css('background-color', '#fff');
})
.on('error', function() {
loading.remove();
node.remove();
})
.appendTo(preview)
.attr('src', opts.url + '#' + url);
preview.one('change', function() {
loading.remove();
node.off('load').remove();
});
}
}
});
}
}
},
/**
* PDF preview plugin
*
* @param elFinder.commands.quicklook
**/
function(ql) {
var fm = ql.fm,
mime = 'application/pdf',
preview = ql.preview,
active = false,
urlhash = '',
firefox, toolbar;
if ((fm.UA.Safari && fm.OS === 'mac' && !fm.UA.iOS) || fm.UA.IE || fm.UA.Firefox) {
active = true;
} else {
$.each(navigator.plugins, function(i, plugins) {
$.each(plugins, function(i, plugin) {
if (plugin.type === mime) {
return !(active = true);
}
});
});
}
if (active) {
if (typeof ql.options.pdfToolbar !== 'undefined' && !ql.options.pdfToolbar) {
urlhash = '#toolbar=0';
}
preview.on(ql.evUpdate, function(e) {
var file = e.file;
if (active && file.mime === mime && ql.dispInlineRegex.test(file.mime)) {
e.stopImmediatePropagation();
ql.hideinfo();
ql.cover.addClass('elfinder-quicklook-coverbg');
$('<object class="elfinder-quicklook-preview-pdf" data="'+fm.openUrl(file.hash)+urlhash+'" type="application/pdf" />')
.on('error', function(e) {
active = false;
ql.update(void(0), fm.cwd());
ql.update(void(0), file);
})
.appendTo(preview);
}
});
}
},
/**
* Flash preview plugin
*
* @param elFinder.commands.quicklook
**/
function(ql) {
var fm = ql.fm,
mime = 'application/x-shockwave-flash',
preview = ql.preview,
active = false;
$.each(navigator.plugins, function(i, plugins) {
$.each(plugins, function(i, plugin) {
if (plugin.type === mime) {
return !(active = true);
}
});
});
active && preview.on(ql.evUpdate, function(e) {
var file = e.file,
node;
if (file.mime === mime && ql.dispInlineRegex.test(file.mime)) {
e.stopImmediatePropagation();
ql.hideinfo();
node = $('<embed class="elfinder-quicklook-preview-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" src="'+fm.openUrl(file.hash)+'" quality="high" type="application/x-shockwave-flash" wmode="transparent" />')
.appendTo(preview);
}
});
},
/**
* HTML5 audio preview plugin
*
* @param elFinder.commands.quicklook
**/
function(ql) {
var fm = ql.fm,
preview = ql.preview,
mimes = {
'audio/mpeg' : 'mp3',
'audio/mpeg3' : 'mp3',
'audio/mp3' : 'mp3',
'audio/x-mpeg3' : 'mp3',
'audio/x-mp3' : 'mp3',
'audio/x-wav' : 'wav',
'audio/wav' : 'wav',
'audio/x-m4a' : 'm4a',
'audio/aac' : 'm4a',
'audio/mp4' : 'm4a',
'audio/x-mp4' : 'm4a',
'audio/ogg' : 'ogg',
'audio/webm' : 'webm',
'audio/flac' : 'flac',
'audio/x-flac' : 'flac',
'audio/amr' : 'amr'
},
node, curHash,
win = ql.window,
navi = ql.navbar,
AMR, autoplay,
controlsList = typeof ql.options.mediaControlsList === 'string' && ql.options.mediaControlsList? ' controlsList="' + fm.escape(ql.options.mediaControlsList) + '"' : '',
setNavi = function() {
navi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? '50px' : '');
},
getNode = function(src, hash) {
return $('<audio class="elfinder-quicklook-preview-audio ui-front" controls' + controlsList + ' preload="auto" autobuffer><source src="'+src+'" /></audio>')
.on('change', function(e) {
// Firefox fire change event on seek or volume change
e.stopPropagation();
})
.on('error', function(e) {
node && node.data('hash') === hash && reset();
})
.data('hash', hash)
.appendTo(preview);
},
amrToWavUrl = function(hash) {
var dfd = $.Deferred(),
loader = $.Deferred().done(function() {
fm.getContents(hash).done(function(data) {
try {
var buffer = AMR.toWAV(new Uint8Array(data));
if (buffer) {
dfd.resolve(URL.createObjectURL(new Blob([buffer], { type: 'audio/x-wav' })));
} else {
dfd.reject();
}
} catch(e) {
dfd.reject();
}
}).fail(function() {
dfd.reject();
});
}).fail(function() {
AMR = false;
dfd.reject();
}),
_AMR;
if (window.TextEncoder && window.URL && URL.createObjectURL && typeof AMR === 'undefined') {
// previous window.AMR
_AMR = window.AMR;
delete window.AMR;
fm.loadScript(
[ fm.options.cdns.amr ],
function() {
AMR = window.AMR? window.AMR : false;
// restore previous window.AMR
window.AMR = _AMR;
loader[AMR? 'resolve':'reject']();
},
{
error: function() {
loader.reject();
}
}
);
} else {
loader[AMR? 'resolve':'reject']();
}
return dfd;
},
play = function(player) {
var hash = node.data('hash'),
playPromise;
autoplay && (playPromise = player.play());
// uses "playPromise['catch']" instead "playPromise.catch" to support Old IE
if (playPromise && playPromise['catch']) {
playPromise['catch'](function(e) {
if (!player.paused) {
node && node.data('hash') === hash && reset();
}
});
}
},
reset = function() {
if (node && node.parent().length) {
var elm = node[0],
url = node.children('source').attr('src');
win.off('viewchange.audio');
try {
elm.pause();
node.empty();
if (url.match(/^blob:/)) {
URL.revokeObjectURL(url);
}
elm.src = '';
elm.load();
} catch(e) {}
node.remove();
node = null;
}
};
preview.on(ql.evUpdate, function(e) {
var file = e.file,
type = mimes[file.mime],
html5, srcUrl;
if (mimes[file.mime] && ql.dispInlineRegex.test(file.mime) && ((html5 = ql.support.audio[type]) || (type === 'amr'))) {
autoplay = ql.autoPlay();
curHash = file.hash;
srcUrl = html5? fm.openUrl(curHash) : '';
if (!html5) {
if (fm.options.cdns.amr && type === 'amr' && AMR !== false) {
e.stopImmediatePropagation();
node = getNode(srcUrl, curHash);
amrToWavUrl(file.hash).done(function(url) {
if (curHash === file.hash) {
var elm = node[0];
try {
node.children('source').attr('src', url);
elm.pause();
elm.load();
play(elm);
win.on('viewchange.audio', setNavi);
setNavi();
} catch(e) {
URL.revokeObjectURL(url);
node.remove();
}
} else {
URL.revokeObjectURL(url);
}
}).fail(function() {
node.remove();
});
}
} else {
e.stopImmediatePropagation();
node = getNode(srcUrl, curHash);
play(node[0]);
win.on('viewchange.audio', setNavi);
setNavi();
}
}
}).on('change', reset);
},
/**
* HTML5 video preview plugin
*
* @param elFinder.commands.quicklook
**/
function(ql) {
var fm = ql.fm,
preview = ql.preview,
mimes = {
'video/mp4' : 'mp4',
'video/x-m4v' : 'mp4',
'video/quicktime' : 'mp4',
'video/ogg' : 'ogg',
'application/ogg' : 'ogg',
'video/webm' : 'webm',
'video/x-matroska': 'mkv',
'video/3gpp' : '3gp',
'application/vnd.apple.mpegurl' : 'm3u8',
'application/x-mpegurl' : 'm3u8',
'application/dash+xml' : 'mpd',
'video/x-flv' : 'flv'
},
node,
win = ql.window,
navi = ql.navbar,
cHls, cDash, pDash, cFlv, autoplay, tm,
controlsList = typeof ql.options.mediaControlsList === 'string' && ql.options.mediaControlsList? ' controlsList="' + fm.escape(ql.options.mediaControlsList) + '"' : '',
setNavi = function() {
if (fm.UA.iOS) {
if (win.hasClass('elfinder-quicklook-fullscreen')) {
preview.css('height', '-webkit-calc(100% - 50px)');
navi._show();
} else {
preview.css('height', '');
}
} else {
navi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? '50px' : '');
}
},
render = function(file, opts) {
var errTm = function(e) {
if (err > 1) {
tm && clearTimeout(tm);
tm = setTimeout(function() {
!canPlay && reset(true);
}, 800);
}
},
err = 0,
canPlay;
//reset();
pDash = null;
opts = opts || {};
ql.hideinfo();
node = $('<video class="elfinder-quicklook-preview-video" controls' + controlsList + ' preload="auto" autobuffer playsinline>'
+'</video>')
.on('change', function(e) {
// Firefox fire change event on seek or volume change
e.stopPropagation();
})
.on('timeupdate progress', errTm)
.on('canplay', function() {
canPlay = true;
})
.data('hash', file.hash);
// can not handling error event with jQuery `on` event handler
node[0].addEventListener('error', function(e) {
if (opts.src && fm.convAbsUrl(opts.src) === fm.convAbsUrl(e.target.src)) {
++err;
errTm();
}
}, true);
if (opts.src) {
node.append('<source src="'+opts.src+'" type="'+file.mime+'"/><source src="'+opts.src+'"/>');
}
node.appendTo(preview);
win.on('viewchange.video', setNavi);
setNavi();
},
loadHls = function(file) {
var hls;
render(file);
hls = new cHls();
hls.loadSource(fm.openUrl(file.hash));
hls.attachMedia(node[0]);
if (autoplay) {
hls.on(cHls.Events.MANIFEST_PARSED, function() {
play(node[0]);
});
}
},
loadDash = function(file) {
render(file);
pDash = window.dashjs.MediaPlayer().create();
pDash.getDebug().setLogToBrowserConsole(false);
pDash.initialize(node[0], fm.openUrl(file.hash), autoplay);
pDash.on('error', function(e) {
reset(true);
});
},
loadFlv = function(file) {
if (!cFlv.isSupported()) {
cFlv = false;
return;
}
var player = cFlv.createPlayer({
type: 'flv',
url: fm.openUrl(file.hash)
});
render(file);
player.on(cFlv.Events.ERROR, function() {
player.destroy();
reset(true);
});
player.attachMediaElement(node[0]);
player.load();
play(player);
},
play = function(player) {
var hash = node.data('hash'),
playPromise;
autoplay && (playPromise = player.play());
// uses "playPromise['catch']" instead "playPromise.catch" to support Old IE
if (playPromise && playPromise['catch']) {
playPromise['catch'](function(e) {
if (!player.paused) {
node && node.data('hash') === hash && reset(true);
}
});
}
},
reset = function(showInfo) {
tm && clearTimeout(tm);
if (node && node.parent().length) {
var elm = node[0];
win.off('viewchange.video');
pDash && pDash.reset();
try {
elm.pause();
node.empty();
elm.src = '';
elm.load();
} catch(e) {}
node.remove();
node = null;
}
showInfo && ql.info.show();
};
preview.on(ql.evUpdate, function(e) {
var file = e.file,
mime = file.mime.toLowerCase(),
type = mimes[mime],
stock, playPromise;
if (mimes[mime] && ql.dispInlineRegex.test(file.mime) && (((type === 'm3u8' || (type === 'mpd' && !fm.UA.iOS) || type === 'flv') && !fm.UA.ltIE10) || ql.support.video[type])) {
autoplay = ql.autoPlay();
if (ql.support.video[type] && (type !== 'm3u8' || fm.UA.Safari)) {
e.stopImmediatePropagation();
render(file, { src: fm.openUrl(file.hash) });
play(node[0]);
} else {
if (cHls !== false && fm.options.cdns.hls && type === 'm3u8') {
e.stopImmediatePropagation();
if (cHls) {
loadHls(file);
} else {
stock = window.Hls;
delete window.Hls;
fm.loadScript(
[ fm.options.cdns.hls ],
function(res) {
cHls = res || window.Hls || false;
window.Hls = stock;
cHls && loadHls(file);
},
{
tryRequire: true,
error : function() {
cHls = false;
}
}
);
}
} else if (cDash !== false && fm.options.cdns.dash && type === 'mpd') {
e.stopImmediatePropagation();
if (cDash) {
loadDash(file);
} else {
fm.loadScript(
[ fm.options.cdns.dash ],
function() {
// dashjs require window.dashjs in global scope
cDash = window.dashjs? true : false;
cDash && loadDash(file);
},
{
tryRequire: true,
error : function() {
cDash = false;
}
}
);
}
} else if (cFlv !== false && fm.options.cdns.flv && type === 'flv') {
e.stopImmediatePropagation();
if (cFlv) {
loadFlv(file);
} else {
stock = window.flvjs;
delete window.flvjs;
fm.loadScript(
[ fm.options.cdns.flv ],
function(res) {
cFlv = res || window.flvjs || false;
window.flvjs = stock;
cFlv && loadFlv(file);
},
{
tryRequire: true,
error : function() {
cFlv = false;
}
}
);
}
}
}
}
}).on('change', reset);
},
/**
* Audio/video preview plugin using browser plugins
*
* @param elFinder.commands.quicklook
**/
function(ql) {
var preview = ql.preview,
mimes = [],
node,
win = ql.window,
navi = ql.navbar;
$.each(navigator.plugins, function(i, plugins) {
$.each(plugins, function(i, plugin) {
(plugin.type.indexOf('audio/') === 0 || plugin.type.indexOf('video/') === 0) && mimes.push(plugin.type);
});
});
mimes = ql.fm.arrayFlip(mimes);
preview.on(ql.evUpdate, function(e) {
var file = e.file,
mime = file.mime,
video,
setNavi = function() {
navi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? '50px' : '');
};
if (mimes[file.mime] && ql.dispInlineRegex.test(file.mime)) {
e.stopImmediatePropagation();
(video = mime.indexOf('video/') === 0) && ql.hideinfo();
node = $('<embed src="'+ql.fm.openUrl(file.hash)+'" type="'+mime+'" class="elfinder-quicklook-preview-'+(video ? 'video' : 'audio')+'"/>')
.appendTo(preview);
win.on('viewchange.embed', setNavi);
setNavi();
}
}).on('change', function() {
if (node && node.parent().length) {
win.off('viewchange.embed');
node.remove();
node= null;
}
});
},
/**
* Archive(zip|gzip|tar) preview plugin using https://github.com/imaya/zlib.js
*
* @param elFinder.commands.quicklook
**/
function(ql) {
var fm = ql.fm,
mimes = fm.arrayFlip(['application/zip', 'application/x-gzip', 'application/x-tar']),
preview = ql.preview,
unzipFiles = function() {
/** @type {Array.<string>} */
var filenameList = [];
/** @type {number} */
var i;
/** @type {number} */
var il;
/** @type {Array.<Zlib.Unzip.FileHeader>} */
var fileHeaderList;
// need check this.Y when update cdns.zlibUnzip
this.Y();
fileHeaderList = this.i;
for (i = 0, il = fileHeaderList.length; i < il; ++i) {
// need check fileHeaderList[i].J when update cdns.zlibUnzip
filenameList[i] = fileHeaderList[i].filename + (fileHeaderList[i].J? ' (' + fm.formatSize(fileHeaderList[i].J) + ')' : '');
}
return filenameList;
},
tarFiles = function(tar) {
var filenames = [],
tarlen = tar.length,
offset = 0,
toStr = function(arr) {
return String.fromCharCode.apply(null, arr).replace(/\0+$/, '');
},
h, name, prefix, size, dbs;
while (offset < tarlen && tar[offset] !== 0) {
h = tar.subarray(offset, offset + 512);
name = toStr(h.subarray(0, 100));
if (prefix = toStr(h.subarray(345, 500))) {
name = prefix + name;
}
size = parseInt(toStr(h.subarray(124, 136)), 8);
dbs = Math.ceil(size / 512) * 512;
if (name === '././@LongLink') {
name = toStr(tar.subarray(offset + 512, offset + 512 + dbs));
}
(name !== 'pax_global_header') && filenames.push(name + (size? ' (' + fm.formatSize(size) + ')': ''));
offset = offset + 512 + dbs;
}
return filenames;
},
Zlib;
if (window.Uint8Array && window.DataView && fm.options.cdns.zlibUnzip && fm.options.cdns.zlibGunzip) {
preview.on(ql.evUpdate, function(e) {
var file = e.file,
isTar = (file.mime === 'application/x-tar');
if (mimes[file.mime] && (
isTar
|| ((typeof Zlib === 'undefined' || Zlib) && (file.mime === 'application/zip' || file.mime === 'application/x-gzip'))
)) {
var jqxhr, loading, url,
req = function() {
url = fm.openUrl(file.hash);
if (!fm.isSameOrigin(url)) {
url = fm.openUrl(file.hash, true);
}
jqxhr = fm.request({
data : {cmd : 'get'},
options : {
url: url,
type: 'get',
cache : true,
dataType : 'binary',
responseType :'arraybuffer',
processData: false
}
})
.fail(function() {
loading.remove();
})
.done(function(data) {
var unzip, filenames;
try {
if (file.mime === 'application/zip') {
unzip = new Zlib.Unzip(new Uint8Array(data));
//filenames = unzip.getFilenames();
filenames = unzipFiles.call(unzip);
} else if (file.mime === 'application/x-gzip') {
unzip = new Zlib.Gunzip(new Uint8Array(data));
filenames = tarFiles(unzip.decompress());
} else if (file.mime === 'application/x-tar') {
filenames = tarFiles(new Uint8Array(data));
}
makeList(filenames);
} catch (e) {
loading.remove();
fm.debug('error', e);
}
});
},
makeList = function(filenames) {
var header, doc;
if (filenames && filenames.length) {
filenames = $.map(filenames, function(str) {
return fm.decodeRawString(str);
});
filenames.sort();
loading.remove();
header = '<strong>'+fm.escape(file.mime)+'</strong> ('+fm.formatSize(file.size)+')'+'<hr/>';
doc = $('<div class="elfinder-quicklook-preview-archive-wrapper">'+header+'<pre class="elfinder-quicklook-preview-text">'+fm.escape(filenames.join("\n"))+'</pre></div>')
.on('touchstart', function(e) {
if ($(this)['scroll' + (fm.direction === 'ltr'? 'Right' : 'Left')]() > 5) {
e.originalEvent._preventSwipeX = true;
}
})
.appendTo(preview);
ql.hideinfo();
}
},
_Zlib;
// this is our file - stop event propagation
e.stopImmediatePropagation();
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"/></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
// stop loading on change file if not loaded yet
preview.one('change', function() {
jqxhr.state() === 'pending' && jqxhr.reject();
loading.remove();
});
if (Zlib) {
req();
} else {
if (window.Zlib) {
_Zlib = window.Zlib;
delete window.Zlib;
}
fm.loadScript(
[ fm.options.cdns.zlibUnzip, fm.options.cdns.zlibGunzip ],
function() {
if (window.Zlib && (Zlib = window.Zlib)) {
if (_Zlib) {
window.Zlib = _Zlib;
} else {
delete window.Zlib;
}
req();
} else {
error();
}
}
);
}
}
});
}
},
/**
* RAR Archive preview plugin using https://github.com/43081j/rar.js
*
* @param elFinder.commands.quicklook
**/
function(ql) {
var fm = ql.fm,
mimes = fm.arrayFlip(['application/x-rar']),
preview = ql.preview,
RAR;
if (window.DataView) {
preview.on(ql.evUpdate, function(e) {
var file = e.file;
if (mimes[file.mime] && fm.options.cdns.rar && RAR !== false) {
var loading, url, archive, abort,
getList = function(url) {
if (abort) {
loading.remove();
return;
}
try {
archive = RAR({
file: url,
type: 2,
xhrHeaders: fm.customHeaders,
xhrFields: fm.xhrFields
}, function(err) {
loading.remove();
var filenames = [],
header, doc;
if (abort || err) {
// An error occurred (not a rar, read error, etc)
err && fm.debug('error', err);
return;
}
$.each(archive.entries, function() {
filenames.push(this.path + (this.size? ' (' + fm.formatSize(this.size) + ')' : ''));
});
if (filenames.length) {
filenames = $.map(filenames, function(str) {
return fm.decodeRawString(str);
});
filenames.sort();
header = '<strong>'+fm.escape(file.mime)+'</strong> ('+fm.formatSize(file.size)+')'+'<hr/>';
doc = $('<div class="elfinder-quicklook-preview-archive-wrapper">'+header+'<pre class="elfinder-quicklook-preview-text">'+fm.escape(filenames.join("\n"))+'</pre></div>')
.on('touchstart', function(e) {
if ($(this)['scroll' + (fm.direction === 'ltr'? 'Right' : 'Left')]() > 5) {
e.originalEvent._preventSwipeX = true;
}
})
.appendTo(preview);
ql.hideinfo();
}
});
} catch(e) {
loading.remove();
}
},
error = function() {
RAR = false;
loading.remove();
},
_RAR;
// this is our file - stop event propagation
e.stopImmediatePropagation();
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"/></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
// stop loading on change file if not loaded yet
preview.one('change', function() {
archive && (archive.abort = true);
loading.remove();
abort = true;
});
url = fm.openUrl(file.hash);
if (!fm.isSameOrigin(url)) {
url = fm.openUrl(file.hash, true);
}
if (RAR) {
getList(url);
} else {
if (window.RarArchive) {
_RAR = window.RarArchive;
delete window.RarArchive;
}
fm.loadScript(
[ fm.options.cdns.rar ],
function() {
if (fm.hasRequire) {
require(['rar'], function(RarArchive) {
RAR = RarArchive;
getList(url);
}, error);
} else {
if (RAR = window.RarArchive) {
if (_RAR) {
window.RarArchive = _RAR;
} else {
delete window.RarArchive;
}
getList(url);
} else {
error();
}
}
},
{
tryRequire: true,
error : error
}
);
}
}
});
}
},
/**
* CAD-Files and 3D-Models online viewer on sharecad.org
*
* @param elFinder.commands.quicklook
**/
function(ql) {
var fm = ql.fm,
mimes = fm.arrayFlip(ql.options.sharecadMimes || []),
preview = ql.preview,
win = ql.window,
node;
if (ql.options.sharecadMimes.length) {
ql.addIntegration({
title: 'ShareCAD.org CAD and 3D-Models viewer',
link: 'https://sharecad.org/DWGOnlinePlugin'
});
}
preview.on(ql.evUpdate, function(e) {
var file = e.file;
if (mimes[file.mime.toLowerCase()]) {
var win = ql.window,
loading, url;
e.stopImmediatePropagation();
if (file.url == '1') {
preview.hide();
$('<div class="elfinder-quicklook-info-data"><button class="elfinder-info-button">'+fm.i18n('getLink')+'</button></div>').appendTo(ql.info.find('.elfinder-quicklook-info'))
.on('click', function() {
var self = $(this);
self.html('<span class="elfinder-spinner">');
fm.request({
data : {cmd : 'url', target : file.hash},
preventDefault : true
})
.always(function() {
self.html('');
})
.done(function(data) {
var rfile = fm.file(file.hash);
file.url = rfile.url = data.url || '';
if (file.url) {
preview.trigger({
type: ql.evUpdate,
file: file,
forceUpdate: true
});
}
});
});
}
if (file.url !== '' && file.url != '1') {
preview.one('change', function() {
loading.remove();
node.off('load').remove();
node = null;
}).addClass('elfinder-overflow-auto');
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"/></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
url = fm.convAbsUrl(fm.url(file.hash));
node = $('<iframe class="elfinder-quicklook-preview-iframe" scrolling="no"/>')
.css('background-color', 'transparent')
.appendTo(preview)
.on('load', function() {
ql.hideinfo();
loading.remove();
ql.preview.after(ql.info);
$(this).css('background-color', '#fff').show();
})
.on('error', function() {
loading.remove();
ql.preview.after(ql.info);
})
.attr('src', '//sharecad.org/cadframe/load?url=' + encodeURIComponent(url));
ql.info.after(ql.preview);
}
}
});
},
/**
* KML preview with GoogleMaps API
*
* @param elFinder.commands.quicklook
*/
function(ql) {
var fm = ql.fm,
mimes = {
'application/vnd.google-earth.kml+xml' : true,
'application/vnd.google-earth.kmz' : true
},
preview = ql.preview,
gMaps, loadMap, wGmfail, fail, mapScr;
if (ql.options.googleMapsApiKey) {
ql.addIntegration({
title: 'Google Maps',
link: 'https://www.google.com/intl/' + fm.lang.replace('_', '-') + '/help/terms_maps.html'
});
gMaps = (window.google && google.maps);
// start load maps
loadMap = function(file, node) {
var mapsOpts = ql.options.googleMapsOpts.maps;
ql.hideinfo();
try {
new gMaps.KmlLayer(fm.convAbsUrl(fm.url(file.hash)), Object.assign({
map: new gMaps.Map(node.get(0), mapsOpts)
}, ql.options.googleMapsOpts.kml));
} catch(e) {
fail();
}
};
// keep stored error handler if exists
wGmfail = window.gm_authFailure;
// on error function
fail = function() {
mapScr = null;
};
// API script url
mapScr = 'https://maps.googleapis.com/maps/api/js?key=' + ql.options.googleMapsApiKey;
// error handler
window.gm_authFailure = function() {
fail();
wGmfail && wGmfail();
};
preview.on(ql.evUpdate, function(e) {
var file = e.file;
if (mapScr && mimes[file.mime.toLowerCase()]) {
var win = ql.window,
loading, url, node;
e.stopImmediatePropagation();
if (file.url == '1') {
preview.hide();
$('<div class="elfinder-quicklook-info-data"><button class="elfinder-info-button">'+fm.i18n('getLink')+'</button></div>').appendTo(ql.info.find('.elfinder-quicklook-info'))
.on('click', function() {
var self = $(this);
self.html('<span class="elfinder-spinner">');
fm.request({
data : {cmd : 'url', target : file.hash},
preventDefault : true
})
.always(function() {
self.html('');
})
.done(function(data) {
var rfile = fm.file(file.hash);
file.url = rfile.url = data.url || '';
if (file.url) {
preview.trigger({
type: ql.evUpdate,
file: file,
forceUpdate: true
});
}
});
});
}
if (file.url !== '' && file.url != '1') {
node = $('<div style="width:100%;height:100%;"/>').appendTo(preview);
preview.one('change', function() {
node.remove();
node = null;
});
if (!gMaps) {
fm.loadScript([mapScr], function() {
gMaps = window.google && google.maps;
gMaps && loadMap(file, node);
});
} else {
loadMap(file, node);
}
}
}
});
}
},
/**
* Any supported files preview plugin using (Google docs | MS Office) online viewer
*
* @param elFinder.commands.quicklook
**/
function(ql) {
var fm = ql.fm,
mimes = Object.assign(fm.arrayFlip(ql.options.googleDocsMimes || [], 'g'), fm.arrayFlip(ql.options.officeOnlineMimes || [], 'm')),
preview = ql.preview,
win = ql.window,
navi = ql.navbar,
urls = {
g: 'docs.google.com/gview?embedded=true&url=',
m: 'view.officeapps.live.com/op/embed.aspx?wdStartOn=0&src='
},
navBottom = {
g: '56px',
m: '24px'
},
mLimits = {
xls : 5242880, // 5MB
xlsb : 5242880,
xlsx : 5242880,
xlsm : 5242880,
other: 10485760 // 10MB
},
node, enable;
if (ql.options.googleDocsMimes.length) {
enable = true;
ql.addIntegration({
title: 'Google Docs Viewer',
link: 'https://docs.google.com/'
});
}
if (ql.options.officeOnlineMimes.length) {
enable = true;
ql.addIntegration({
title: 'MS Online Doc Viewer',
link: 'https://products.office.com/office-online/view-office-documents-online'
});
}
if (enable) {
preview.on(ql.evUpdate, function(e) {
var file = e.file,
type;
// 25MB is maximum filesize of Google Docs prevew
if (file.size <= 26214400 && (type = mimes[file.mime])) {
var win = ql.window,
setNavi = function() {
navi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? navBottom[type] : '');
},
ext = fm.mimeTypes[file.mime],
loading, url;
if (type === 'm') {
if ((mLimits[ext] && file.size > mLimits[ext]) || file.size > mLimits.other) {
type = 'g';
}
}
if (file.url == '1') {
preview.hide();
$('<div class="elfinder-quicklook-info-data"><button class="elfinder-info-button">'+fm.i18n('getLink')+'</button></div>').appendTo(ql.info.find('.elfinder-quicklook-info'))
.on('click', function() {
var self = $(this);
self.html('<span class="elfinder-spinner">');
fm.request({
data : {cmd : 'url', target : file.hash},
preventDefault : true
})
.always(function() {
self.html('');
})
.done(function(data) {
var rfile = fm.file(file.hash);
file.url = rfile.url = data.url || '';
if (file.url) {
preview.trigger({
type: ql.evUpdate,
file: file,
forceUpdate: true
});
}
});
});
}
if (file.url !== '' && file.url != '1') {
e.stopImmediatePropagation();
preview.one('change', function() {
win.off('viewchange.googledocs');
loading.remove();
node.off('load').remove();
node = null;
}).addClass('elfinder-overflow-auto');
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"/></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
url = fm.convAbsUrl(fm.url(file.hash));
if (file.ts) {
url += (url.match(/\?/)? '&' : '?') + '_t=' + file.ts;
}
node = $('<iframe class="elfinder-quicklook-preview-iframe"/>')
.css('background-color', 'transparent')
.appendTo(preview)
.on('load', function() {
ql.hideinfo();
loading.remove();
ql.preview.after(ql.info);
$(this).css('background-color', '#fff').show();
})
.on('error', function() {
loading.remove();
ql.preview.after(ql.info);
})
.attr('src', 'https://' + urls[type] + encodeURIComponent(url));
win.on('viewchange.googledocs', setNavi);
setNavi();
ql.info.after(ql.preview);
}
}
});
}
},
/**
* Texts preview plugin
*
* @param elFinder.commands.quicklook
**/
function(ql) {
var fm = ql.fm,
preview = ql.preview,
textMaxlen = parseInt(ql.options.textMaxlen) || 2000,
prettify = function() {
if (fm.options.cdns.prettify) {
fm.loadScript([fm.options.cdns.prettify + (fm.options.cdns.prettify.match(/\?/)? '&' : '?') + 'autorun=false']);
prettify = function() { return true; };
} else {
prettify = function() { return false; };
}
},
PRcheck = function(node, cnt) {
if (prettify()) {
if (typeof window.PR === 'undefined' && cnt--) {
setTimeout(function() { PRcheck(node, cnt); }, 100);
} else {
if (typeof window.PR === 'object') {
node.css('cursor', 'wait');
requestAnimationFrame(function() {
PR.prettyPrint && PR.prettyPrint(null, node.get(0));
node.css('cursor', '');
});
} else {
prettify = function() { return false; };
}
}
}
};
preview.on(ql.evUpdate, function(e) {
var file = e.file,
mime = file.mime,
jqxhr, loading;
if (fm.mimeIsText(file.mime) && (!ql.options.getSizeMax || file.size <= ql.options.getSizeMax)) {
e.stopImmediatePropagation();
(typeof window.PR === 'undefined') && prettify();
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"/></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
// stop loading on change file if not loadin yet
preview.one('change', function() {
jqxhr.state() == 'pending' && jqxhr.reject();
});
jqxhr = fm.request({
data : {cmd : 'get', target : file.hash, conv : 1, _t : file.ts},
options : {type: 'get', cache : true},
preventDefault : true
})
.done(function(data) {
var reg = new RegExp('^(data:'+file.mime.replace(/([.+])/g, '\\$1')+';base64,)', 'i'),
text = data.content,
part, more, node, m;
ql.hideinfo();
if (window.atob && (m = text.match(reg))) {
text = atob(text.substr(m[1].length));
}
more = text.length - textMaxlen;
if (more > 100) {
part = text.substr(0, textMaxlen) + '...';
} else {
more = 0;
}
node = $('<div class="elfinder-quicklook-preview-text-wrapper"><pre class="elfinder-quicklook-preview-text prettyprint"></pre></div>');
if (more) {
node.append($('<div class="elfinder-quicklook-preview-charsleft"><hr/><span>' + fm.i18n('charsLeft', fm.toLocaleString(more)) + '</span></div>')
.on('click', function() {
var top = node.scrollTop();
$(this).remove();
node.children('pre').removeClass('prettyprinted').text(text).scrollTop(top);
PRcheck(node, 100);
})
);
}
node.children('pre').text(part || text);
node.on('touchstart', function(e) {
if ($(this)['scroll' + (fm.direction === 'ltr'? 'Right' : 'Left')]() > 5) {
e.originalEvent._preventSwipeX = true;
}
}).appendTo(preview);
PRcheck(node, 100);
})
.always(function() {
loading.remove();
});
}
});
}
];
/*
* File: /js/commands/reload.js
*/
/**
* @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/>')
.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
/*
* File: /js/commands/rename.js
*/
/**
* @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)) {
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/>').append(
mkChk(num, 'plusNumber'),
mkChk(prefix, 'asPrefix'),
mkChk(suffix, 'asSuffix'),
mkChk(extention, 'changeExtention')
),
preview = $('<div class="elfinder-rename-batch-preview"/>'),
node = $('<div class="elfinder-rename-batch"/>').append(
$('<div class="elfinder-rename-batch-name"/>').append(name),
$('<div class="elfinder-rename-batch-type"/>').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 && (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/>')
.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? 'navHash2Id' : 'cwdHash2Id'](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/>' : '<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);
}
});
};
/*
* File: /js/commands/resize.js
*/
/**
* @class elFinder command "resize"
* Open dialog to resize image
*
* @author Dmitry (dio) Levashov
* @author Alexey Sukhotin
* @author Naoki Sawada
* @author Sergio Jovani
**/
elFinder.prototype.commands.resize = function() {
"use strict";
var losslessRotate = 0,
getBounceBox = function(w, h, theta) {
var srcPts = [
{x: w/2, y: h/2},
{x: -w/2, y: h/2},
{x: -w/2, y: -h/2},
{x: w/2, y: -h/2}
],
dstPts = [],
min = {x: Number.MAX_VALUE, y: Number.MAX_VALUE},
max = {x: Number.MIN_VALUE, y: Number.MIN_VALUE};
$.each(srcPts, function(i, srcPt){
dstPts.push({
x: srcPt.x * Math.cos(theta) - srcPt.y * Math.sin(theta),
y: srcPt.x * Math.sin(theta) + srcPt.y * Math.cos(theta)
});
});
$.each(dstPts, function(i, pt) {
min.x = Math.min(min.x, pt.x);
min.y = Math.min(min.y, pt.y);
max.x = Math.max(max.x, pt.x);
max.y = Math.max(max.y, pt.y);
});
return {
width: max.x - min.x, height: max.y - min.y
};
};
this.updateOnSelect = false;
this.getstate = function() {
var sel = this.fm.selectedFiles();
return sel.length == 1 && sel[0].read && sel[0].write && sel[0].mime.indexOf('image/') !== -1 ? 0 : -1;
};
this.resizeRequest = function(data, f, dfrd) {
var fm = this.fm,
file = f || fm.file(data.target),
tmb = file? file.tmb : null,
enabled = fm.isCommandEnabled('resize', data.target);
if (enabled && (! file || (file && file.read && file.write && file.mime.indexOf('image/') !== -1 ))) {
return fm.request({
data : Object.assign(data, {
cmd : 'resize'
}),
notify : {type : 'resize', cnt : 1}
})
.fail(function(error) {
if (dfrd) {
dfrd.reject(error);
}
})
.done(function() {
if (data.quality) {
fm.storage('jpgQuality', data.quality === fm.option('jpgQuality')? null : data.quality);
}
dfrd && dfrd.resolve();
});
} else {
var error;
if (file) {
if (file.mime.indexOf('image/') === -1) {
error = ['errResize', file.name, 'errUsupportType'];
} else {
error = ['errResize', file.name, 'errPerm'];
}
} else {
error = ['errResize', data.target, 'errPerm'];
}
if (dfrd) {
dfrd.reject(error);
} else {
fm.error(error);
}
return $.Deferred().reject(error);
}
};
this.exec = function(hashes) {
var self = this,
fm = this.fm,
files = this.files(hashes),
dfrd = $.Deferred(),
api2 = (fm.api > 1),
options = this.options,
dialogWidth = 650,
fmnode = fm.getUI(),
ctrgrup = $().controlgroup? 'controlgroup' : 'buttonset',
grid8Def = typeof options.grid8px === 'undefined' || options.grid8px !== 'disable'? true : false,
presetSize = Array.isArray(options.presetSize)? options.presetSize : [],
clactive = 'elfinder-dialog-active',
clsediting = fm.res('class', 'editing'),
open = function(file, id) {
var isJpeg = (file.mime === 'image/jpeg'),
dialog = $('<div class="elfinder-resize-container"/>'),
input = '<input type="number" class="ui-corner-all"/>',
row = '<div class="elfinder-resize-row"/>',
label = '<div class="elfinder-resize-label"/>',
changeTm = null,
operate = false,
opStart = function() { operate = true; },
opStop = function() {
if (operate) {
operate = false;
control.trigger('change');
}
},
control = $('<div class="elfinder-resize-control"/>')
.on('focus', 'input[type=text],input[type=number]', function() {
$(this).trigger('select');
})
.on('change', function() {
changeTm && cancelAnimationFrame(changeTm);
changeTm = requestAnimationFrame(function() {
var panel, quty, canvas, ctx, img, sx, sy, sw, sh, deg, theta, bb;
if (sizeImg && ! operate && (canvas = sizeImg.data('canvas'))) {
panel = control.children('div.elfinder-resize-control-panel:visible');
quty = panel.find('input.elfinder-resize-quality');
if (quty.is(':visible')) {
ctx = sizeImg.data('ctx');
img = sizeImg.get(0);
if (panel.hasClass('elfinder-resize-uiresize')) {
// resize
sw = canvas.width = width.val();
sh = canvas.height = height.val();
ctx.drawImage(img, 0, 0, sw, sh);
} else if (panel.hasClass('elfinder-resize-uicrop')) {
// crop
sx = pointX.val();
sy = pointY.val();
sw = offsetX.val();
sh = offsetY.val();
canvas.width = sw;
canvas.height = sh;
ctx.drawImage(img, sx, sy, sw, sh, 0, 0, sw, sh);
} else {
// rotate
deg = degree.val();
theta = (degree.val() * Math.PI) / 180;
bb = getBounceBox(owidth, oheight, theta);
sw = canvas.width = bb.width;
sh = canvas.height = bb.height;
ctx.save();
if (deg % 90 !== 0) {
ctx.fillStyle = bg.val() || '#FFF';
ctx.fillRect(0, 0, sw, sh);
}
ctx.translate(sw / 2, sh / 2);
ctx.rotate(theta);
ctx.drawImage(img, -img.width/2, -img.height/2, owidth, oheight);
ctx.restore();
}
canvas.toBlob(function(blob) {
blob && quty.next('span').text(' (' + fm.formatSize(blob.size) + ')');
}, 'image/jpeg', Math.max(Math.min(quty.val(), 100), 1) / 100);
}
}
});
})
.on('mouseup', 'input', function(e) {
$(e.target).trigger('change');
}),
preview = $('<div class="elfinder-resize-preview"/>')
.on('touchmove', function(e) {
if ($(e.target).hasClass('touch-punch')) {
e.stopPropagation();
e.preventDefault();
}
}),
spinner = $('<div class="elfinder-resize-loading">'+fm.i18n('ntfloadimg')+'</div>'),
rhandle = $('<div class="elfinder-resize-handle touch-punch"/>'),
rhandlec = $('<div class="elfinder-resize-handle touch-punch"/>'),
uiresize = $('<div class="elfinder-resize-uiresize elfinder-resize-control-panel"/>'),
uicrop = $('<div class="elfinder-resize-uicrop elfinder-resize-control-panel"/>'),
uirotate = $('<div class="elfinder-resize-rotate elfinder-resize-control-panel"/>'),
uideg270 = $('<button/>').attr('title',fm.i18n('rotate-cw')).append($('<span class="elfinder-button-icon elfinder-button-icon-rotate-l"/>')),
uideg90 = $('<button/>').attr('title',fm.i18n('rotate-ccw')).append($('<span class="elfinder-button-icon elfinder-button-icon-rotate-r"/>')),
uiprop = $('<span />'),
reset = $('<button class="elfinder-resize-reset">').text(fm.i18n('reset'))
.on('click', function() {
resetView();
})
.button({
icons: {
primary: 'ui-icon-arrowrefresh-1-n'
},
text: false
}),
uitype = $('<div class="elfinder-resize-type"/>')
.append('<input type="radio" name="type" id="'+id+'-resize" value="resize" checked="checked" /><label for="'+id+'-resize">'+fm.i18n('resize')+'</label>',
'<input class="api2" type="radio" name="type" id="'+id+'-crop" value="crop" /><label class="api2" for="'+id+'-crop">'+fm.i18n('crop')+'</label>',
'<input class="api2" type="radio" name="type" id="'+id+'-rotate" value="rotate" /><label class="api2" for="'+id+'-rotate">'+fm.i18n('rotate')+'</label>'),
mode = 'resize',
type = uitype[ctrgrup]()[ctrgrup]('disable').find('input')
.on('change', function() {
mode = $(this).val();
resetView();
resizable(true);
croppable(true);
rotateable(true);
if (mode == 'resize') {
uiresize.show();
uirotate.hide();
uicrop.hide();
resizable();
isJpeg && grid8px.insertAfter(uiresize.find('.elfinder-resize-grid8'));
}
else if (mode == 'crop') {
uirotate.hide();
uiresize.hide();
uicrop.show();
croppable();
isJpeg && grid8px.insertAfter(uicrop.find('.elfinder-resize-grid8'));
} else if (mode == 'rotate') {
uiresize.hide();
uicrop.hide();
uirotate.show();
rotateable();
}
}),
width = $(input)
.on('change', function() {
var w = round(parseInt(width.val())),
h = round(cratio ? w/ratio : parseInt(height.val()));
if (w > 0 && h > 0) {
resize.updateView(w, h);
width.val(w);
height.val(h);
}
}).addClass('elfinder-focus'),
height = $(input)
.on('change', function() {
var h = round(parseInt(height.val())),
w = round(cratio ? h*ratio : parseInt(width.val()));
if (w > 0 && h > 0) {
resize.updateView(w, h);
width.val(w);
height.val(h);
}
}),
pointX = $(input).on('change', function(){crop.updateView();}),
pointY = $(input).on('change', function(){crop.updateView();}),
offsetX = $(input).on('change', function(){crop.updateView('w');}),
offsetY = $(input).on('change', function(){crop.updateView('h');}),
quality = isJpeg && api2?
$(input).val(fm.storage('jpgQuality') > 0? fm.storage('jpgQuality') : fm.option('jpgQuality'))
.addClass('elfinder-resize-quality')
.attr('min', '1').attr('max', '100').attr('title', '1 - 100')
.on('blur', function(){
var q = Math.min(100, Math.max(1, parseInt(this.value)));
control.find('input.elfinder-resize-quality').val(q);
})
: null,
degree = $('<input type="number" class="ui-corner-all" maxlength="3" value="0" />')
.on('change', function() {
rotate.update();
}),
uidegslider = $('<div class="elfinder-resize-rotate-slider touch-punch"/>')
.slider({
min: 0,
max: 360,
value: degree.val(),
animate: true,
start: opStart,
stop: opStop,
change: function(event, ui) {
if (ui.value != uidegslider.slider('value')) {
rotate.update(ui.value);
}
},
slide: function(event, ui) {
rotate.update(ui.value, false);
}
}).find('.ui-slider-handle')
.addClass('elfinder-tabstop')
.off('keydown')
.on('keydown', function(e) {
if (e.keyCode == $.ui.keyCode.LEFT || e.keyCode == $.ui.keyCode.RIGHT) {
e.stopPropagation();
e.preventDefault();
rotate.update(Number(degree.val()) + (e.keyCode == $.ui.keyCode.RIGHT? 1 : -1), false);
}
})
.end(),
pickimg,
pickcanv,
pickctx,
pickc = {},
pick = function(e) {
var color, r, g, b, h, s, l;
try {
color = pickc[Math.round(e.offsetX)][Math.round(e.offsetY)];
} catch(e) {}
if (!color) return;
r = color[0]; g = color[1]; b = color[2];
h = color[3]; s = color[4]; l = color[5];
setbg(r, g, b, (e.type === 'click'));
},
palpick = function(e) {
setbg($(this).css('backgroundColor'), '', '', (e.type === 'click'));
},
setbg = function(r, g, b, off) {
var s, m, cc;
if (typeof r === 'string') {
g = '';
if (r && (s = $('<span>').css('backgroundColor', r).css('backgroundColor')) && (m = s.match(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i))) {
r = Number(m[1]);
g = Number(m[2]);
b = Number(m[3]);
}
}
cc = (g === '')? r : '#' + getColorCode(r, g, b);
bg.val(cc).css({ backgroundColor: cc, backgroundImage: 'none', color: (r+g+b < 384? '#fff' : '#000') });
preview.css('backgroundColor', cc);
if (off) {
imgr.off('.picker').removeClass('elfinder-resize-picking');
pallet.off('.picker').removeClass('elfinder-resize-picking');
}
},
getColorCode = function(r, g, b) {
return $.map([r,g,b], function(c){return ('0'+parseInt(c).toString(16)).slice(-2);}).join('');
},
picker = $('<button>').text(fm.i18n('colorPicker'))
.on('click', function() {
imgr.on('mousemove.picker click.picker', pick).addClass('elfinder-resize-picking');
pallet.on('mousemove.picker click.picker', 'span', palpick).addClass('elfinder-resize-picking');
})
.button({
icons: {
primary: 'ui-icon-pin-s'
},
text: false
}),
reseter = $('<button>').text(fm.i18n('reset'))
.on('click', function() {
setbg('', '', '', true);
})
.button({
icons: {
primary: 'ui-icon-arrowrefresh-1-n'
},
text: false
}),
bg = $('<input class="ui-corner-all elfinder-resize-bg" type="text">')
.on('focus', function() {
$(this).attr('style', '');
})
.on('blur', function() {
setbg($(this).val());
}),
pallet = $('<div class="elfinder-resize-pallet">').on('click', 'span', function() {
setbg($(this).css('backgroundColor'));
}),
ratio = 1,
prop = 1,
owidth = 0,
oheight = 0,
cratio = true,
cratioc = false,
pwidth = 0,
pheight = 0,
rwidth = 0,
rheight = 0,
rdegree = 0,
grid8 = isJpeg? grid8Def : false,
constr = $('<button>').html(fm.i18n('aspectRatio'))
.on('click', function() {
cratio = ! cratio;
constr.button('option', {
icons : { primary: cratio? 'ui-icon-locked' : 'ui-icon-unlocked'}
});
resize.fixHeight();
rhandle.resizable('option', 'aspectRatio', cratio).data('uiResizable')._aspectRatio = cratio;
})
.button({
icons : {
primary: cratio? 'ui-icon-locked' : 'ui-icon-unlocked'
},
text: false
}),
constrc = $('<button>').html(fm.i18n('aspectRatio'))
.on('click', function() {
cratioc = ! cratioc;
constrc.button('option', {
icons : { primary: cratioc? 'ui-icon-locked' : 'ui-icon-unlocked'}
});
rhandlec.resizable('option', 'aspectRatio', cratioc).data('uiResizable')._aspectRatio = cratioc;
})
.button({
icons : {
primary: cratioc? 'ui-icon-locked' : 'ui-icon-unlocked'
},
text: false
}),
grid8px = $('<button>').html(fm.i18n(grid8? 'enabled' : 'disabled')).toggleClass('ui-state-active', grid8)
.on('click', function() {
grid8 = ! grid8;
grid8px.html(fm.i18n(grid8? 'enabled' : 'disabled')).toggleClass('ui-state-active', grid8);
setStep8();
})
.button(),
setStep8 = function() {
var step = grid8? 8 : 1;
$.each([width, height, offsetX, offsetY, pointX, pointY], function() {
this.attr('step', step);
});
if (grid8) {
width.val(round(width.val()));
height.val(round(height.val()));
offsetX.val(round(offsetX.val()));
offsetY.val(round(offsetY.val()));
pointX.val(round(pointX.val()));
pointY.val(round(pointY.val()));
if (uiresize.is(':visible')) {
resize.updateView(width.val(), height.val());
} else if (uicrop.is(':visible')) {
crop.updateView();
}
}
},
setuprimg = function() {
var r_scale,
fail = function() {
bg.parent().hide();
pallet.hide();
};
r_scale = Math.min(pwidth, pheight) / Math.sqrt(Math.pow(owidth, 2) + Math.pow(oheight, 2));
rwidth = Math.ceil(owidth * r_scale);
rheight = Math.ceil(oheight * r_scale);
imgr.width(rwidth)
.height(rheight)
.css('margin-top', (pheight-rheight)/2 + 'px')
.css('margin-left', (pwidth-rwidth)/2 + 'px');
if (imgr.is(':visible') && bg.is(':visible')) {
if (file.mime !== 'image/png') {
preview.css('backgroundColor', bg.val());
pickimg = $('<img>');
if (fm.isCORS) {
pickimg.attr('crossorigin', 'use-credentials');
}
pickimg.on('load', function() {
if (pickcanv && pickcanv.width !== rwidth) {
setColorData();
}
})
.on('error', fail)
.attr('src', canvSrc);
} else {
fail();
}
}
},
setupimg = function() {
resize.updateView(owidth, oheight);
setuprimg();
basec
.width(img.width())
.height(img.height());
imgc
.width(img.width())
.height(img.height());
crop.updateView();
jpgCalc();
},
setColorData = function() {
if (pickctx) {
var n, w, h, r, g, b, a, s, l, hsl, hue,
data, scale, tx1, tx2, ty1, ty2, rgb,
domi = {},
domic = [],
domiv, palc,
rgbToHsl = function (r, g, b) {
var h, s, l,
max = Math.max(Math.max(r, g), b),
min = Math.min(Math.min(r, g), b);
// Hue, 0 ~ 359
if (max === min) {
h = 0;
} else if (r === max) {
h = ((g - b) / (max - min) * 60 + 360) % 360;
} else if (g === max) {
h = (b - r) / (max - min) * 60 + 120;
} else if (b === max) {
h = (r - g) / (max - min) * 60 + 240;
}
// Saturation, 0 ~ 1
s = (max - min) / max;
// Lightness, 0 ~ 1
l = (r * 0.3 + g * 0.59 + b * 0.11) / 255;
return [h, s, l, 'hsl'];
},
rgbRound = function(c) {
return Math.round(c / 8) * 8;
};
calc:
try {
w = pickcanv.width = imgr.width();
h = pickcanv.height = imgr.height();
scale = w / owidth;
pickctx.scale(scale, scale);
pickctx.drawImage(pickimg.get(0), 0, 0);
data = pickctx.getImageData(0, 0, w, h).data;
// Range to detect the dominant color
tx1 = w * 0.1;
tx2 = w * 0.9;
ty1 = h * 0.1;
ty2 = h * 0.9;
for (var y = 0; y < h - 1; y++) {
for (var x = 0; x < w - 1; x++) {
n = x * 4 + y * w * 4;
// RGB
r = data[n]; g = data[n + 1]; b = data[n + 2]; a = data[n + 3];
// check alpha ch
if (a !== 255) {
bg.parent().hide();
pallet.hide();
break calc;
}
// HSL
hsl = rgbToHsl(r, g, b);
hue = Math.round(hsl[0]); s = Math.round(hsl[1] * 100); l = Math.round(hsl[2] * 100);
if (! pickc[x]) {
pickc[x] = {};
}
// set pickc
pickc[x][y] = [r, g, b, hue, s, l];
// detect the dominant color
if ((x < tx1 || x > tx2) && (y < ty1 || y > ty2)) {
rgb = rgbRound(r) + ',' + rgbRound(g) + ',' + rgbRound(b);
if (! domi[rgb]) {
domi[rgb] = 1;
} else {
++domi[rgb];
}
}
}
}
if (! pallet.children(':first').length) {
palc = 1;
$.each(domi, function(c, v) {
domic.push({c: c, v: v});
});
$.each(domic.sort(function(a, b) {
return (a.v > b.v)? -1 : 1;
}), function() {
if (this.v < 2 || palc > 10) {
return false;
}
pallet.append($('<span style="width:20px;height:20px;display:inline-block;background-color:rgb('+this.c+');">'));
++palc;
});
}
} catch(e) {
picker.hide();
pallet.hide();
}
}
},
setupPicker = function() {
try {
pickcanv = document.createElement('canvas');
pickctx = pickcanv.getContext('2d');
} catch(e) {
picker.hide();
pallet.hide();
}
},
setupPreset = function() {
preset.on('click', 'span.elfinder-resize-preset', function() {
var btn = $(this),
w = btn.data('s')[0],
h = btn.data('s')[1],
r = owidth / oheight;
btn.data('s', [h, w]).text(h + 'x' + w);
if (owidth > w || oheight > h) {
if (owidth <= w) {
w = round(h * r);
} else if (oheight <= h) {
h = round(w / r);
} else {
if (owidth - w > oheight - h) {
h = round(w / r);
} else {
w = round(h * r);
}
}
} else {
w = owidth;
h = oheight;
}
width.val(w);
height.val(h);
resize.updateView(w, h);
jpgCalc();
});
presetc.on('click', 'span.elfinder-resize-preset', function() {
var btn = $(this),
w = btn.data('s')[0],
h = btn.data('s')[1],
x = pointX.val(),
y = pointY.val();
btn.data('s', [h, w]).text(h + 'x' + w);
if (owidth >= w && oheight >= h) {
if (owidth - w - x < 0) {
x = owidth - w;
}
if (oheight - h - y < 0) {
y = oheight - h;
}
pointX.val(x);
pointY.val(y);
offsetX.val(w);
offsetY.val(h);
crop.updateView();
jpgCalc();
}
});
presetc.children('span.elfinder-resize-preset').each(function() {
var btn = $(this),
w = btn.data('s')[0],
h = btn.data('s')[1];
btn[(owidth >= w && oheight >= h)? 'show' : 'hide']();
});
},
dimreq = null,
inited = false,
setdim = function(dim) {
var rfile = fm.file(file.hash);
rfile.width = dim[0];
rfile.height = dim[1];
},
init = function() {
var elm, memSize, r_scale, imgRatio;
if (inited) {
return;
}
inited = true;
dimreq && dimreq.state && dimreq.state() === 'pending' && dimreq.reject();
// check lossless rotete
if (fm.api >= 2.1030) {
if (losslessRotate === 0) {
fm.request({
data: {
cmd : 'resize',
target : file.hash,
degree : 0,
mode : 'rotate'
},
preventDefault : true
}).done(function(data) {
losslessRotate = data.losslessRotate? 1 : -1;
if (losslessRotate === 1 && (degree.val() % 90 === 0)) {
uirotate.children('div.elfinder-resize-quality').hide();
}
}).fail(function() {
losslessRotate = -1;
});
}
} else {
losslessRotate = -1;
}
elm = img.get(0);
memSize = file.width && file.height? {w: file.width, h: file.height} : (elm.naturalWidth? null : {w: img.width(), h: img.height()});
memSize && img.removeAttr('width').removeAttr('height');
owidth = file.width || elm.naturalWidth || elm.width || img.width();
oheight = file.height || elm.naturalHeight || elm.height || img.height();
if (!file.width || !file.height) {
setdim([owidth, oheight]);
}
memSize && img.width(memSize.w).height(memSize.h);
dMinBtn.show();
imgRatio = oheight / owidth;
if (imgRatio < 1 && preview.height() > preview.width() * imgRatio) {
preview.height(preview.width() * imgRatio);
}
if (preview.height() > img.height() + 20) {
preview.height(img.height() + 20);
}
pheight = preview.height() - (rhandle.outerHeight() - rhandle.height());
spinner.remove();
ratio = owidth/oheight;
rhandle.append(img.show()).show();
width.val(owidth);
height.val(oheight);
setupPicker();
setupPreset();
setupimg();
uitype[ctrgrup]('enable');
control.find('input,select').prop('disabled', false)
.filter(':text').on('keydown', function(e) {
var cOpts;
if (e.keyCode == $.ui.keyCode.ENTER) {
e.stopPropagation();
e.preventDefault();
cOpts = {
title : $('input:checked', uitype).val(),
text : 'confirmReq',
accept : {
label : 'btnApply',
callback : function() {
save();
}
},
cancel : {
label : 'btnCancel',
callback : function(){
$(this).trigger('focus');
}
}
};
if (useSaveAs) {
cOpts['buttons'] = [{
label : 'btnSaveAs',
callback : function() {
requestAnimationFrame(saveAs);
}
}];
}
fm.confirm(cOpts);
return;
}
})
.on('keyup', function() {
var $this = $(this);
if (! $this.hasClass('elfinder-resize-bg')) {
requestAnimationFrame(function() {
$this.val($this.val().replace(/[^0-9]/g, ''));
});
}
})
.filter(':first');
setStep8();
!fm.UA.Mobile && width.trigger('focus');
resizable();
},
img = $('<img/>')
.on('load', init)
.on('error', function() {
spinner.text('Unable to load image').css('background', 'transparent');
}),
basec = $('<div/>'),
imgc = $('<img/>'),
coverc = $('<div/>'),
imgr = $('<img class="elfinder-resize-imgrotate" />'),
round = function(v, max) {
v = grid8? Math.round(v/8)*8 : Math.round(v);
v = Math.max(0, v);
if (max && v > max) {
v = grid8? Math.floor(max/8)*8 : max;
}
return v;
},
resetView = function() {
width.val(owidth);
height.val(oheight);
resize.updateView(owidth, oheight);
pointX.val(0);
pointY.val(0);
offsetX.val(owidth);
offsetY.val(oheight);
crop.updateView();
jpgCalc();
},
resize = {
update : function() {
width.val(round(img.width()/prop));
height.val(round(img.height()/prop));
jpgCalc();
},
updateView : function(w, h) {
if (w > pwidth || h > pheight) {
if (w / pwidth > h / pheight) {
prop = pwidth / w;
img.width(pwidth).height(round(h*prop));
} else {
prop = pheight / h;
img.height(pheight).width(round(w*prop));
}
} else {
img.width(round(w)).height(round(h));
}
prop = img.width()/w;
uiprop.text('1 : '+(1/prop).toFixed(2));
resize.updateHandle();
},
updateHandle : function() {
rhandle.width(img.width()).height(img.height());
},
fixHeight : function() {
var w, h;
if (cratio) {
w = width.val();
h = round(w/ratio);
resize.updateView(w, h);
height.val(h);
}
}
},
crop = {
update : function(change) {
pointX.val(round(((rhandlec.data('x')||rhandlec.position().left))/prop, owidth));
pointY.val(round(((rhandlec.data('y')||rhandlec.position().top))/prop, oheight));
if (change !== 'xy') {
offsetX.val(round((rhandlec.data('w')||rhandlec.width())/prop, owidth - pointX.val()));
offsetY.val(round((rhandlec.data('h')||rhandlec.height())/prop, oheight - pointY.val()));
}
jpgCalc();
},
updateView : function(change) {
var r, x, y, w, h;
pointX.val(round(pointX.val(), owidth - (grid8? 8 : 1)));
pointY.val(round(pointY.val(), oheight - (grid8? 8 : 1)));
offsetX.val(round(offsetX.val(), owidth - pointX.val()));
offsetY.val(round(offsetY.val(), oheight - pointY.val()));
if (cratioc) {
r = coverc.width() / coverc.height();
if (change === 'w') {
offsetY.val(round(parseInt(offsetX.val()) / r));
} else if (change === 'h') {
offsetX.val(round(parseInt(offsetY.val()) * r));
}
}
x = Math.round(parseInt(pointX.val()) * prop);
y = Math.round(parseInt(pointY.val()) * prop);
if (change !== 'xy') {
w = Math.round(parseInt(offsetX.val()) * prop);
h = Math.round(parseInt(offsetY.val()) * prop);
} else {
w = rhandlec.data('w');
h = rhandlec.data('h');
}
rhandlec.data({x: x, y: y, w: w, h: h})
.width(w)
.height(h)
.css({left: x, top: y});
coverc.width(w)
.height(h);
},
resize_update : function(e, ui) {
rhandlec.data({x: ui.position.left, y: ui.position.top, w: ui.size.width, h: ui.size.height});
crop.update();
crop.updateView();
},
drag_update : function(e, ui) {
rhandlec.data({x: ui.position.left, y: ui.position.top});
crop.update('xy');
}
},
rotate = {
mouseStartAngle : 0,
imageStartAngle : 0,
imageBeingRotated : false,
setQuality : function() {
uirotate.children('div.elfinder-resize-quality')[(losslessRotate > 0 && (degree.val() % 90) === 0)? 'hide' : 'show']();
},
update : function(value, animate) {
if (typeof value == 'undefined') {
rdegree = value = parseInt(degree.val());
}
if (typeof animate == 'undefined') {
animate = true;
}
if (! animate || fm.UA.Opera || fm.UA.ltIE8) {
imgr.rotate(value);
} else {
imgr.animate({rotate: value + 'deg'});
}
value = value % 360;
if (value < 0) {
value += 360;
}
degree.val(parseInt(value));
uidegslider.slider('value', degree.val());
rotate.setQuality();
},
execute : function ( e ) {
if ( !rotate.imageBeingRotated ) return;
var imageCentre = rotate.getCenter( imgr );
var ev = e.originalEvent.touches? e.originalEvent.touches[0] : e;
var mouseXFromCentre = ev.pageX - imageCentre[0];
var mouseYFromCentre = ev.pageY - imageCentre[1];
var mouseAngle = Math.atan2( mouseYFromCentre, mouseXFromCentre );
var rotateAngle = mouseAngle - rotate.mouseStartAngle + rotate.imageStartAngle;
rotateAngle = Math.round(parseFloat(rotateAngle) * 180 / Math.PI);
if ( e.shiftKey ) {
rotateAngle = Math.round((rotateAngle + 6)/15) * 15;
}
imgr.rotate(rotateAngle);
rotateAngle = rotateAngle % 360;
if (rotateAngle < 0) {
rotateAngle += 360;
}
degree.val(rotateAngle);
uidegslider.slider('value', degree.val());
rotate.setQuality();
return false;
},
start : function ( e ) {
if (imgr.hasClass('elfinder-resize-picking')) {
return;
}
opStart();
rotate.imageBeingRotated = true;
var imageCentre = rotate.getCenter( imgr );
var ev = e.originalEvent.touches? e.originalEvent.touches[0] : e;
var mouseStartXFromCentre = ev.pageX - imageCentre[0];
var mouseStartYFromCentre = ev.pageY - imageCentre[1];
rotate.mouseStartAngle = Math.atan2( mouseStartYFromCentre, mouseStartXFromCentre );
rotate.imageStartAngle = parseFloat(imgr.rotate()) * Math.PI / 180.0;
$(document).on('mousemove', rotate.execute);
imgr.on('touchmove', rotate.execute);
return false;
},
stop : function ( e ) {
if ( !rotate.imageBeingRotated ) return;
$(document).off('mousemove', rotate.execute);
imgr.off('touchmove', rotate.execute);
requestAnimationFrame(function() { rotate.imageBeingRotated = false; });
opStop();
return false;
},
getCenter : function ( image ) {
var currentRotation = imgr.rotate();
imgr.rotate(0);
var imageOffset = imgr.offset();
var imageCentreX = imageOffset.left + imgr.width() / 2;
var imageCentreY = imageOffset.top + imgr.height() / 2;
imgr.rotate(currentRotation);
return Array( imageCentreX, imageCentreY );
}
},
resizable = function(destroy) {
if (destroy) {
rhandle.filter(':ui-resizable').resizable('destroy');
rhandle.hide();
}
else {
rhandle.show();
rhandle.resizable({
alsoResize : img,
aspectRatio : cratio,
resize : resize.update,
start : opStart,
stop : function(e) {
resize.fixHeight;
resize.updateView(width.val(), height.val());
opStop();
}
});
dinit();
}
},
croppable = function(destroy) {
if (destroy) {
rhandlec.filter(':ui-resizable').resizable('destroy')
.filter(':ui-draggable').draggable('destroy');
basec.hide();
}
else {
basec.show();
rhandlec
.resizable({
containment : basec,
aspectRatio : cratioc,
resize : crop.resize_update,
start : opStart,
stop : opStop,
handles : 'all'
})
.draggable({
handle : coverc,
containment : imgc,
drag : crop.drag_update,
start : opStart,
stop : function() {
crop.updateView('xy');
opStop();
}
});
dinit();
crop.update();
}
},
rotateable = function(destroy) {
if (destroy) {
imgr.hide();
}
else {
imgr.show();
dinit();
}
},
checkVals = function() {
var w, h, x, y, d, q, b = '';
if (mode == 'resize') {
w = parseInt(width.val()) || 0;
h = parseInt(height.val()) || 0;
} else if (mode == 'crop') {
w = parseInt(offsetX.val()) || 0;
h = parseInt(offsetY.val()) || 0;
x = parseInt(pointX.val()) || 0;
y = parseInt(pointY.val()) || 0;
} else if (mode == 'rotate') {
w = owidth;
h = oheight;
d = parseInt(degree.val()) || 0;
if (d < 0 || d > 360) {
fm.error('Invalid rotate degree');
return false;
}
if (d == 0 || d == 360) {
fm.error('errResizeNoChange');
return false;
}
b = bg.val();
}
q = quality? parseInt(quality.val()) : 0;
if (mode != 'rotate') {
if (w <= 0 || h <= 0) {
fm.error('Invalid image size');
return false;
}
if (w == owidth && h == oheight) {
fm.error('errResizeNoChange');
return false;
}
}
return {w: w, h: h, x: x, y: y, d: d, q: q, b: b};
},
save = function() {
var vals;
if (vals = checkVals()) {
dialog.elfinderdialog('close');
self.resizeRequest({
target : file.hash,
width : vals.w,
height : vals.h,
x : vals.x,
y : vals.y,
degree : vals.d,
quality: vals.q,
bg : vals.b,
mode : mode
}, file, dfrd);
}
},
saveAs = function() {
var fail = function() {
dialogs.addClass(clsediting).fadeIn(function() {
base.addClass(clactive);
});
fm.disable();
},
make = function() {
self.mime = file.mime;
self.prefix = file.name.replace(/ \d+(\.[^.]+)?$/, '$1');
self.requestCmd = 'mkfile';
self.nextAction = {};
self.data = {target : file.phash};
$.proxy(fm.res('mixin', 'make'), self)()
.done(function(data) {
var hash, dfd;
if (data.added && data.added.length) {
hash = data.added[0].hash;
dfd = fm.api < 2.1032? fm.url(file.hash, { async: true, temporary: true }) : null;
$.when(dfd).done(function(url) {
fm.request({
options : {type : 'post'},
data : {
cmd : 'put',
target : hash,
encoding: dfd? 'scheme' : 'hash',
content : dfd? fm.convAbsUrl(url) : file.hash
},
notify : {type : 'copy', cnt : 1},
syncOnFail : true
})
.fail(fail)
.done(function(data) {
data = fm.normalize(data);
fm.updateCache(data);
file = fm.file(hash);
data.changed && data.changed.length && fm.change(data);
base.show().find('.elfinder-dialog-title').html(fm.escape(file.name));
save();
dialogs.fadeIn();
});
}).fail(fail);
} else {
fail();
}
})
.fail(fail)
.always(function() {
delete self.mime;
delete self.prefix;
delete self.nextAction;
delete self.data;
});
fm.trigger('unselectfiles', { files: [ file.hash ] });
},
reqOpen = null,
dialogs;
if (checkVals()) {
dialogs = fmnode.children('.' + self.dialogClass + ':visible').removeClass(clsediting).fadeOut();
base.removeClass(clactive);
fm.enable();
if (fm.searchStatus.state < 2 && file.phash !== fm.cwd().hash) {
reqOpen = fm.exec('open', [file.phash], {thash: file.phash});
}
$.when([reqOpen]).done(function() {
reqOpen? fm.one('cwdrender', make) : make();
}).fail(fail);
}
},
buttons = {},
hline = 'elfinder-resize-handle-hline',
vline = 'elfinder-resize-handle-vline',
rpoint = 'elfinder-resize-handle-point',
src = fm.openUrl(file.hash),
canvSrc = fm.openUrl(file.hash, !fm.isSameOrigin(src)),
sizeImg = quality? $('<img>').attr('crossorigin', fm.isCORS? 'use-credentials' : '').attr('src', canvSrc).on('load', function() {
try {
var canv = document.createElement('canvas');
sizeImg.data('canvas', canv).data('ctx', canv.getContext('2d'));
jpgCalc();
} catch(e) {
sizeImg.removeData('canvas').removeData('ctx');
}
}) : null,
jpgCalc = function() {
control.find('input.elfinder-resize-quality:visible').trigger('change');
},
dinit = function(e) {
if (base.hasClass('elfinder-dialog-minimized') || base.is(':hidden')) {
return;
}
preset.hide();
presetc.hide();
var win = fm.options.dialogContained? fmnode : $(window),
winH = win.height(),
winW = win.width(),
presW = 'auto',
presIn = true,
dw, ctrW, prvW;
base.width(Math.min(dialogWidth, winW - 30));
preview.attr('style', '');
if (owidth && oheight) {
pwidth = preview.width() - (rhandle.outerWidth() - rhandle.width());
pheight = preview.height() - (rhandle.outerHeight() - rhandle.height());
resize.updateView(owidth, oheight);
}
ctrW = dialog.find('div.elfinder-resize-control').width();
prvW = preview.width();
dw = dialog.width() - 20;
if (prvW > dw) {
preview.width(dw);
presIn = false;
} else if ((dw - prvW) < ctrW) {
if (winW > winH) {
preview.width(dw - ctrW - 20);
} else {
preview.css({ float: 'none', marginLeft: 'auto', marginRight: 'auto'});
presIn = false;
}
}
if (presIn) {
presW = ctrW;
}
pwidth = preview.width() - (rhandle.outerWidth() - rhandle.width());
if (fmnode.hasClass('elfinder-fullscreen')) {
if (base.height() > winH) {
winH -= 2;
preview.height(winH - base.height() + preview.height());
base.css('top', 0 - fmnode.offset().top);
}
} else {
winH -= 30;
(preview.height() > winH) && preview.height(winH);
}
pheight = preview.height() - (rhandle.outerHeight() - rhandle.height());
if (owidth && oheight) {
setupimg();
}
if (img.height() && preview.height() > img.height() + 20) {
preview.height(img.height() + 20);
pheight = preview.height() - (rhandle.outerHeight() - rhandle.height());
setuprimg();
}
preset.css('width', presW).show();
presetc.css('width', presW).show();
if (!presetc.children('span.elfinder-resize-preset:visible').length) {
presetc.hide();
}
},
preset = (function() {
var sets = $('<fieldset class="elfinder-resize-preset-container">').append($('<legend>').html(fm.i18n('presets'))).hide(),
hasC;
$.each(presetSize, function(i, s) {
if (s.length === 2) {
hasC = true;
sets.append($('<span class="elfinder-resize-preset"/>')
.data('s', s)
.text(s[0]+'x'+s[1])
.button()
);
}
});
if (!hasC) {
return $();
} else {
return sets;
}
})(),
presetc = preset.clone(true),
useSaveAs = fm.uploadMimeCheck(file.mime, file.phash),
dMinBtn, base;
uiresize.append(
$(row).append($(label).text(fm.i18n('width')), width),
$(row).append($(label).text(fm.i18n('height')), height, $('<div class="elfinder-resize-whctrls">').append(constr, reset)),
(quality? $(row).append($(label).text(fm.i18n('quality')), quality, $('<span/>')) : $()),
(isJpeg? $(row).append($(label).text(fm.i18n('8pxgrid')).addClass('elfinder-resize-grid8'), grid8px) : $()),
$(row).append($(label).text(fm.i18n('scale')), uiprop),
$(row).append(preset)
);
if (api2) {
uicrop.append(
$(row).append($(label).text('X'), pointX),
$(row).append($(label).text('Y')).append(pointY),
$(row).append($(label).text(fm.i18n('width')), offsetX),
$(row).append($(label).text(fm.i18n('height')), offsetY, $('<div class="elfinder-resize-whctrls">').append(constrc, reset.clone(true))),
(quality? $(row).append($(label).text(fm.i18n('quality')), quality.clone(true), $('<span/>')) : $()),
(isJpeg? $(row).append($(label).text(fm.i18n('8pxgrid')).addClass('elfinder-resize-grid8')) : $()),
$(row).append(presetc)
);
uirotate.append(
$(row).addClass('elfinder-resize-degree').append(
$(label).text(fm.i18n('rotate')),
degree,
$('<span/>').text(fm.i18n('degree')),
$('<div/>').append(uideg270, uideg90)[ctrgrup]()
),
$(row).css('height', '20px').append(uidegslider),
((quality)? $(row)[losslessRotate < 1? 'show' : 'hide']().addClass('elfinder-resize-quality').append(
$(label).text(fm.i18n('quality')),
quality.clone(true),
$('<span/>')) : $()
),
$(row).append($(label).text(fm.i18n('bgcolor')), bg, picker, reseter),
$(row).css('height', '20px').append(pallet)
);
uideg270.on('click', function() {
rdegree = rdegree - 90;
rotate.update(rdegree);
});
uideg90.on('click', function(){
rdegree = rdegree + 90;
rotate.update(rdegree);
});
}
dialog.append(uitype).on('resize', function(e){
e.stopPropagation();
});
if (api2) {
control.append(/*$(row), */uiresize, uicrop.hide(), uirotate.hide());
} else {
control.append(/*$(row), */uiresize);
}
rhandle.append('<div class="'+hline+' '+hline+'-top"/>',
'<div class="'+hline+' '+hline+'-bottom"/>',
'<div class="'+vline+' '+vline+'-left"/>',
'<div class="'+vline+' '+vline+'-right"/>',
'<div class="'+rpoint+' '+rpoint+'-e"/>',
'<div class="'+rpoint+' '+rpoint+'-se"/>',
'<div class="'+rpoint+' '+rpoint+'-s"/>');
preview.append(spinner).append(rhandle.hide()).append(img.hide());
if (api2) {
rhandlec.css('position', 'absolute')
.append('<div class="'+hline+' '+hline+'-top"/>',
'<div class="'+hline+' '+hline+'-bottom"/>',
'<div class="'+vline+' '+vline+'-left"/>',
'<div class="'+vline+' '+vline+'-right"/>',
'<div class="'+rpoint+' '+rpoint+'-n"/>',
'<div class="'+rpoint+' '+rpoint+'-e"/>',
'<div class="'+rpoint+' '+rpoint+'-s"/>',
'<div class="'+rpoint+' '+rpoint+'-w"/>',
'<div class="'+rpoint+' '+rpoint+'-ne"/>',
'<div class="'+rpoint+' '+rpoint+'-se"/>',
'<div class="'+rpoint+' '+rpoint+'-sw"/>',
'<div class="'+rpoint+' '+rpoint+'-nw"/>');
preview.append(basec.css('position', 'absolute').hide().append(imgc, rhandlec.append(coverc)));
preview.append(imgr.hide());
}
preview.css('overflow', 'hidden');
dialog.append(preview, control);
buttons[fm.i18n('btnApply')] = save;
if (useSaveAs) {
buttons[fm.i18n('btnSaveAs')] = function() { requestAnimationFrame(saveAs); };
}
buttons[fm.i18n('btnCancel')] = function() { dialog.elfinderdialog('close'); };
dialog.find('input,button').addClass('elfinder-tabstop');
base = self.fmDialog(dialog, {
title : fm.escape(file.name),
width : dialogWidth,
resizable : false,
buttons : buttons,
open : function() {
var substituteImg = (fm.option('substituteImg', file.hash) && file.size > options.dimSubImgSize)? true : false,
hasSize = (file.width && file.height)? true : false;
dialog.parent().css('overflow', 'hidden');
dMinBtn = base.find('.ui-dialog-titlebar .elfinder-titlebar-minimize').hide();
fm.bind('resize', dinit);
img.attr('src', src);
imgc.attr('src', src);
imgr.attr('src', src);
if (api2) {
imgr.on('mousedown touchstart', rotate.start)
.on('touchend', rotate.stop);
base.on('mouseup', rotate.stop);
}
if (hasSize && !substituteImg) {
return init();
}
if (file.size > (options.getDimThreshold || 0)) {
dimreq = fm.request({
data : {cmd : 'dim', target : file.hash, substitute : (substituteImg? 400 : '')},
preventDefault : true
})
.done(function(data) {
if (data.dim) {
var dim = data.dim.split('x');
file.width = dim[0];
file.height = dim[1];
setdim(dim);
if (data.url) {
img.attr('src', data.url);
imgc.attr('src', data.url);
imgr.attr('src', data.url);
}
return init();
}
});
} else if (hasSize) {
return init();
}
},
close : function() {
if (api2) {
imgr.off('mousedown touchstart', rotate.start)
.off('touchend', rotate.stop);
$(document).off('mouseup', rotate.stop);
}
fm.unbind('resize', dinit);
$(this).elfinderdialog('destroy');
},
resize : function(e, data) {
if (data && data.minimize === 'off') {
dinit();
}
}
}).attr('id', id).closest('.ui-dialog').addClass(clsediting);
// for IE < 9 dialog mising at open second+ time.
if (fm.UA.ltIE8) {
$('.elfinder-dialog').css('filter', '');
}
coverc.css({ 'opacity': 0.2, 'background-color': '#fff', 'position': 'absolute'}),
rhandlec.css('cursor', 'move');
rhandlec.find('.elfinder-resize-handle-point').css({
'background-color' : '#fff',
'opacity': 0.5,
'border-color':'#000'
});
if (! api2) {
uitype.find('.api2').remove();
}
control.find('input,select').prop('disabled', true);
control.find('input.elfinder-resize-quality')
.next('span').addClass('elfinder-resize-jpgsize').attr('title', fm.i18n('roughFileSize'));
},
id, dialog
;
if (!files.length || files[0].mime.indexOf('image/') === -1) {
return dfrd.reject();
}
id = 'resize-'+fm.namespace+'-'+files[0].hash;
dialog = fmnode.find('#'+id);
if (dialog.length) {
dialog.elfinderdialog('toTop');
return dfrd.resolve();
}
open(files[0], id);
return dfrd;
};
};
(function ($) {
var findProperty = function (styleObject, styleArgs) {
var i = 0 ;
for( i in styleArgs) {
if (typeof styleObject[styleArgs[i]] != 'undefined')
return styleArgs[i];
}
styleObject[styleArgs[i]] = '';
return styleArgs[i];
};
$.cssHooks.rotate = {
get: function(elem, computed, extra) {
return $(elem).rotate();
},
set: function(elem, value) {
$(elem).rotate(value);
return value;
}
};
$.cssHooks.transform = {
get: function(elem, computed, extra) {
var name = findProperty( elem.style ,
['WebkitTransform', 'MozTransform', 'OTransform' , 'msTransform' , 'transform'] );
return elem.style[name];
},
set: function(elem, value) {
var name = findProperty( elem.style ,
['WebkitTransform', 'MozTransform', 'OTransform' , 'msTransform' , 'transform'] );
elem.style[name] = value;
return value;
}
};
$.fn.rotate = function(val) {
var r;
if (typeof val == 'undefined') {
if (!!window.opera) {
r = this.css('transform').match(/rotate\((.*?)\)/);
return ( r && r[1])?
Math.round(parseFloat(r[1]) * 180 / Math.PI) : 0;
} else {
r = this.css('transform').match(/rotate\((.*?)\)/);
return ( r && r[1])? parseInt(r[1]) : 0;
}
}
this.css('transform',
this.css('transform').replace(/none|rotate\(.*?\)/, '') + 'rotate(' + parseInt(val) + 'deg)');
return this;
};
$.fx.step.rotate = function(fx) {
if ( fx.state == 0 ) {
fx.start = $(fx.elem).rotate();
fx.now = fx.start;
}
$(fx.elem).rotate(fx.now);
};
if (typeof window.addEventListener == "undefined" && typeof document.getElementsByClassName == "undefined") { // IE & IE<9
var GetAbsoluteXY = function(element) {
var pnode = element;
var x = pnode.offsetLeft;
var y = pnode.offsetTop;
while ( pnode.offsetParent ) {
pnode = pnode.offsetParent;
if (pnode != document.body && pnode.currentStyle['position'] != 'static') {
break;
}
if (pnode != document.body && pnode != document.documentElement) {
x -= pnode.scrollLeft;
y -= pnode.scrollTop;
}
x += pnode.offsetLeft;
y += pnode.offsetTop;
}
return { x: x, y: y };
};
var StaticToAbsolute = function (element) {
if ( element.currentStyle['position'] != 'static') {
return ;
}
var xy = GetAbsoluteXY(element);
element.style.position = 'absolute' ;
element.style.left = xy.x + 'px';
element.style.top = xy.y + 'px';
};
var IETransform = function(element,transform){
var r;
var m11 = 1;
var m12 = 1;
var m21 = 1;
var m22 = 1;
if (typeof element.style['msTransform'] != 'undefined'){
return true;
}
StaticToAbsolute(element);
r = transform.match(/rotate\((.*?)\)/);
var rotate = ( r && r[1]) ? parseInt(r[1]) : 0;
rotate = rotate % 360;
if (rotate < 0) rotate = 360 + rotate;
var radian= rotate * Math.PI / 180;
var cosX =Math.cos(radian);
var sinY =Math.sin(radian);
m11 *= cosX;
m12 *= -sinY;
m21 *= sinY;
m22 *= cosX;
element.style.filter = (element.style.filter || '').replace(/progid:DXImageTransform\.Microsoft\.Matrix\([^)]*\)/, "" ) +
("progid:DXImageTransform.Microsoft.Matrix(" +
"M11=" + m11 +
",M12=" + m12 +
",M21=" + m21 +
",M22=" + m22 +
",FilterType='bilinear',sizingMethod='auto expand')")
;
var ow = parseInt(element.style.width || element.width || 0 );
var oh = parseInt(element.style.height || element.height || 0 );
radian = rotate * Math.PI / 180;
var absCosX =Math.abs(Math.cos(radian));
var absSinY =Math.abs(Math.sin(radian));
var dx = (ow - (ow * absCosX + oh * absSinY)) / 2;
var dy = (oh - (ow * absSinY + oh * absCosX)) / 2;
element.style.marginLeft = Math.floor(dx) + "px";
element.style.marginTop = Math.floor(dy) + "px";
return(true);
};
var transform_set = $.cssHooks.transform.set;
$.cssHooks.transform.set = function(elem, value) {
transform_set.apply(this, [elem, value] );
IETransform(elem,value);
return value;
};
}
})(jQuery);
/*
* File: /js/commands/restore.js
*/
/**
* @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
/*
* File: /js/commands/rm.js
*/
/**
* @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"/>{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"/>',
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() {
// re-assign for extended command
self = this;
fm = this.fm;
// bind function of change
self.change(function() {
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 (self.value === 'trash') {
self.extra = {
icon: 'rm',
node: $('<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});
})
};
}
});
};
this.getstate = function(select) {
var sel = this.hashes(select);
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, 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');
}
});
};
/*
* File: /js/commands/search.js
*/
/**
* @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;
};
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) {
$.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 : (reqDef.length? 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();
};
};
/*
* File: /js/commands/selectall.js
*/
/**
* @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();
};
};
/*
* File: /js/commands/selectinvert.js
*/
/**
* @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();
};
};
/*
* File: /js/commands/selectnone.js
*/
/**
* @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();
};
};
/*
* File: /js/commands/sort.js
*/
/**
* @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"/>' : '') + '&nbsp;' + fm.i18n('sortFoldersFirst')
]);
if (fm.ui.tree) {
self.variants.push('|');
self.variants.push([
'tree',
(fm.sortAlsoTreeview? '<span class="ui-icon ui-icon-check"/>' : '') + '&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"/>');
}
} else if (name === (i18Name.tree || (i18Name.tree = fm.i18n('sortAlsoTreeview')))) {
if (fm.sortAlsoTreeview) {
tgt.prepend('<span class="ui-icon ui-icon-check"/>');
}
} 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('toolbar').find('.elfiner-button-sort .elfinder-button-menu .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+'"/>').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();
});
};
};
/*
* File: /js/commands/undo.js
*/
/**
* @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();
}
};
};
/*
* File: /js/commands/up.js
*/
/**
* @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
/*
* File: /js/commands/upload.js
*/
/**
* @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/>').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') + '"/>')
.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" />');
},
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/>').append(input);
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) {
if (e.target === this) {
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 = (trf.items && trf.items.length && trf.items[0].kind)? trf.items[0].kind : '',
errors;
if (trf) {
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[0].getAsEntry || trf.items[0].webkitGetAsEntry)) {
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"/>')
.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.navHash2Id(targetDir.hash)).hasClass('elfinder-subtree-loaded')) {
getSelector().appendTo(dialog);
} else {
spinner = $('<div class="elfinder-upload-dirselect" title="' + fm.i18n('nowLoading') + '"/>')
.append('<span class="elfinder-button-icon elfinder-button-icon-spinner" />')
.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;
};
};
/*
* File: /js/commands/view.js
*/
/**
* @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/>')
.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 = fm.storage('view', this.value == 'list' ? 'icons' : 'list');
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/>')
.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
});
})
};
});
};
return elFinder;
}));