: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
// mark as loaded to cwd parents
current.parents('.elfinder-navbar-wrapper').children('.'+navdir).addClass(loaded);
fm.lazy(open).done(function() {
rmSpinner = function(fail) {
baseNode.addClass(collapsed + (fail? '' : (' ' + loaded)));
dfrd = jQuery.Deferred(),
if (!fm.navHash2Elm(cwdhash).length) {
// trigger 'treesync' with my jQuery.Deferred
fm.trigger('treesync', dfrd);
* Make writable and not root dirs droppable
updateDroppable = function(target, node) {
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+')');
node.children('div.'+wrapperRoot).each(function() {
updateDroppable(null, jQuery(this));
// make droppable on async
fm.asyncJob(function(elm) {
jQuery(elm).droppable(droppableopts);
}, jQuery.makeArray(target), {
* Check required folders for subfolders and update arrow classes
* @param Array folders to check
* @param String css class
updateArrows = function(dirs, cls) {
? '.'+collapsed+':not(.'+loaded+')'
: ':not(.'+collapsed+')';
jQuery.each(dirs, function(i, dir) {
fm.navHash2Elm(dir.phash).filter(sel)
.filter(function() { return jQuery.grep(jQuery(this).next('.'+subtree).children(), function(n) {
return (jQuery(n).children().hasClass(root))? false : true;
tree = jQuery(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; }
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', (hash = fm.navId2Hash(link.attr('id'))))) {
link.draggable(fm.draggable);
link.toggleClass(hover, enter);
// update title attr if necessary
if (enter && opts.attrTitle) {
dir = fm.file(hash || fm.navId2Hash(link.attr('id')));
if (!dir.isroot && link.attr('title') === (dir.i18 || dir.name)) {
link.attr('title', fm.path(hash, true));
.on('dragenter', selNavdir, function(e) {
if (e.originalEvent.dataTransfer) {
if (dst.is('.'+collapsed+':not(.'+expanded+')')) {
dst.data('expandTimer', setTimeout(function() {
dst.is('.'+collapsed+'.'+hover) && dst.children('.'+arrow).trigger('click');
.on('dragleave', selNavdir, function(e) {
if (e.originalEvent.dataTransfer) {
dst.data('expandTimer') && clearTimeout(dst.data('expandTimer'));
// open dir or open subfolders in tree
.on('click', selNavdir, function(e) {
hash = fm.navId2Hash(link.attr('id')),
if (link.data('longtap')) {
link.removeData('longtap');
if (!link.hasClass(active)) {
tree.find(selNavdir+'.'+active).removeClass(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'});
if (link.hasClass(collapsed)) {
link.children('.'+arrow).trigger('click');
fm.select({selected: [hash], origin: 'navbar'});
.on('touchstart', selNavdir, function(e) {
if (e.originalEvent.touches.length > 1) {
var evt = e.originalEvent,
if (e.target.nodeName === 'INPUT') {
p = jQuery(this).addClass(hover)
.data('tmlongtap', setTimeout(function(e){
fm.trigger('contextmenu', {
'targets' : [fm.navId2Hash(p.attr('id'))],
'x' : evt.touches[0].pageX,
'y' : evt.touches[0].pageY
.on('touchmove touchend', selNavdir, function(e) {
if (e.target.nodeName === 'INPUT') {
clearTimeout(jQuery(this).data('tmlongtap'));
jQuery(this).removeData('tmlongtap');
if (e.type == 'touchmove') {
jQuery(this).removeClass(hover);
// toggle subfolders in tree
.on('click', selNavdir+'.'+collapsed+' .'+arrow, function(e) {
var arrow = jQuery(this),
link = arrow.parent(selNavdir),
stree = link.next('.'+subtree),
dfrd = jQuery.Deferred(),
if (link.hasClass(loaded)) {
link.toggleClass(expanded);
cnt = link.hasClass(expanded)? stree.children().length + stree.find('div.elfinder-navbar-subtree[style*=block]').children().length : stree.find('div:visible').length;
fm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
stree.stop(true, true)[link.hasClass(expanded)? 'slideDown' : 'slideUp'](opts.durations.slideUpDown, function(){
fm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
spinner.insertBefore(arrow);
link.removeClass(collapsed);
fm.request({cmd : 'tree', target : fm.navId2Hash(link.attr('id'))})
updateTree(Object.assign([], filter(data.tree)));
if (stree.children().length) {
link.addClass(collapsed+' '+expanded);
if (stree.children().length > slideTH) {
fm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
stree.stop(true, true).slideDown(opts.durations.slideUpDown, function(){
fm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
fm.one('treedone', function() {
arrow.data('dfrd', dfrd);
.on('contextmenu', selNavdir, function(e) {
if (self.find('input:text').length) {
if (!self.data('tmlongtap')) {
fm.trigger('contextmenu', {
'targets' : [fm.navId2Hash(jQuery(this).attr('id'))],
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) {
autoScroll(self.attr('id')).done(function() {
if (!data || data.blink === 'undefined' || data.blink) {
fm.resources.blink(self, 'lookme');
.on('create.'+fm.namespace, function(e, item) {
var pdir = findSubtree(item.phash),
lock = item.move || false,
dir = jQuery(itemhtml(item)).addClass('elfinder-navbar-wrapper-tmp'),
selected = fm.selected();
lock && selected.length && fm.trigger('lockfiles', {files: selected});
navbar = fm.getUI('navbar').append(tree).show().on('scroll', function() {
navbarScrTm && cancelAnimationFrame(navbarScrTm);
navbarScrTm = requestAnimationFrame(function() {
prevSortTreeview = fm.sortAlsoTreeview;
dirs = filter(data.files),
contextmenu = fm.getUI('contextmenu');
data.init && tree.empty();
navbar.removeClass('overflow-scrolling-touch').addClass('overflow-scrolling-touch');
if (!contextmenu.data('cmdMaps')) {
contextmenu.data('cmdMaps', {});
updateArrows(dirs, loaded);
var dirs = filter(e.data.added);
updateArrows(dirs, collapsed);
// do ot perfome while syncing
var dirs = filter(e.data.changed, true),
dir, phash, node, tmp, realParent, reqParent, realSibling, reqSibling, isExpanded, isLoaded, parent, subdirs;
jQuery.each(hasMoreDirs, function(h, node) {
node.trigger('update.'+fm.namespace, { change: 'prepare' });
if ((node = fm.navHash2Elm(dir.hash)).length) {
realParent = node.closest('.'+subtree);
reqParent = findSubtree(phash);
realSibling = node.parent().next();
reqSibling = findSibling(reqParent, dir);
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 = jQuery(itemhtml(dir));
node.replaceWith(tmp.children(selNavdir));
! mobile && updateDroppable(null, parent);
&& (isExpanded || isLoaded)
&& (node = fm.navHash2Elm(dir.hash))
&& node.next('.'+subtree).children().length) {
isExpanded && node.addClass(expanded);
isLoaded && node.addClass(loaded);
subdirs |= dir.dirs == -1;
jQuery.each(hasMoreDirs, function(h, node) {
node.trigger('update.'+fm.namespace, { change: 'done' });
length && sync(void(0), false);
var dirs = e.data.removed,
jQuery.each(hasMoreDirs, function(h, node) {
node.trigger('update.'+fm.namespace, { removed : dirs });
node.trigger('update.'+fm.namespace, { change: 'prepare' });
if ((node = fm.navHash2Elm(dirs[l])).length) {
stree = node.closest('.'+subtree);
if (!stree.children().length) {
stree.hide().prev(selNavdir).removeClass(collapsed+' '+expanded+' '+loaded);
removed && fm.getUI('navbar').children('.ui-resizable-handle').trigger('resize');
jQuery.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 = jQuery.grep(e.data.files||[], function(h) {
return dir && dir.mime == 'directory' ? true : false;
jQuery.each(dirs, function(i, hash) {
var dir = fm.navHash2Elm(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) {