: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
updateTree = function(dirs) {
var length = dirs.length,
append = function(parent, dirs, start, direction) {
max = fm.newAPI? Math.min(10000, Math.max(10, opts.subTreeMax)) : 10000,
jQuery.each(dirs, function(i, d) {
change = function(mode) {
if (mode === 'prepare') {
jQuery.each(dirs, function(i, d) {
d.node && parent.append(d.node.hide());
} else if (mode === 'done') {
jQuery.each(dirs, function(i, d) {
d.node && d.node.detach().show();
update = function(e, data) {
render(getStart(data.select));
if (data.removed && data.removed.length) {
dirs = jQuery.grep(dirs, function(d) {
if (data.removed.indexOf(d.hash) === -1) {
!changed && (changed = true);
if (data.added && data.added.length) {
dirs = dirs.concat(jQuery.grep(data.added, function(d) {
if (hashes[d.hash] === void(0)) {
!changed && (changed = true);
getStart = function(target) {
if (hashes[target] !== void(0)) {
return Math.floor(hashes[target] / max) * max;
target = fm.navId2Hash(parent.prev('[id]').attr('id')),
render = function(start, direction) {
total, page, s, parts, prev, next, prevBtn, nextBtn;
delete hasMoreDirs[target];
parent.off('update.'+fm.namespace, update);
parent.on('update.'+fm.namespace, update);
start = getStart(cwd.hash);
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);
jQuery.each(parts || dirs, function(i, d) {
prevBtn = jQuery('<button class="elfinder-navbar-pager elfinder-navbar-pager-prev"></button>')
.text(fm.i18n('btnPrevious', page, total))
primary: "ui-icon-caret-1-n"
.on('click', function(e) {
nextBtn = jQuery('<button class="elfinder-navbar-pager elfinder-navbar-pager-next"></button>')
.text(fm.i18n('btnNext', page + 2, total))
primary: "ui-icon-caret-1-s"
.on('click', function(e) {
parent.empty()[parts? 'addClass' : 'removeClass']('elfinder-navbar-hasmore').append(prevBtn, html.join(''), nextBtn);
jQuery.each(nodes, function(h, n) {
fm.navHash2Elm(h).parent().replaceWith(n);
autoScroll(fm.navHash2Id(parts[direction === 'up'? parts.length - 1 : 0].hash));
! mobile && fm.lazy(function() { updateDroppable(null, parent); });
jQuery.each(parent.children('.elfinder-navbar-wrapper'), function(i, elm) {
ch = n.children('[id]:first'),
if (ch.hasClass(loaded)) {
h = fm.navId2Hash(ch.attr('id'));
if (h && (c = hashes[h]) !== void(0)) {
dirs[c].node = n.detach();
dir, html, parent, sibling, init, atonce = {}, updates = [], base, node,
if (done[dir.hash] || fm.navHash2Elm(dir.hash).length) {
if ((parent = findSubtree(dir.phash)).length) {
lastKey = dir.phash || 'treeroot';
if (typeof lastNodes[lastKey] === 'undefined') {
lastNodes[lastKey] = parent.children(':last');
init = !lastNodes[lastKey].length;
if (dir.phash && (init || parent.hasClass('elfinder-navbar-hasmore') || (sibling = findSibling(parent, dir)).length)) {
if (!atonce[dir.phash]) {
atonce[dir.phash].push(dir);
! mobile && (tgts = tgts.add(node));
lastNodes[lastKey].after(node);
if (!dir.phash || dir.isroot) {
base = fm.navHash2Elm(dir.hash).parent();
! mobile && updateDroppable(null, base);
// When init, html append at once
if (Object.keys(atonce).length){
jQuery.each(atonce, function(p, dirs){
var parent = findSubtree(p),
parent.trigger('update.' + fm.namespace, { added : updates });
if (orphans.length && orphans.length < length) {
! 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);
var asc = fm.sortOrder == 'asc',
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)
* @return Object jQuery Deferred
autoScroll = function(target) {
var dfrd = jQuery.Deferred(),
current, parent, top, treeH, bottom, tgtTop;
autoScrTm && clearTimeout(autoScrTm);
autoScrTm = setTimeout(function() {
current = jQuery(document.getElementById((target || fm.navHash2Id(fm.cwd().hash))));
// 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;
bottom = top + treeH - current.outerHeight();
tgtTop = current.offset().top;
if (tgtTop < top || tgtTop > bottom) {
scrollTop : parent.scrollTop() + tgtTop - top - treeH / 3
duration : opts.durations.autoScroll,
complete : function() { dfrd.resolve(); }
* Get hashes array of items of the bottom of the leaf root back from the target
* @param Object elFinder item(directory) object
res = cur.hash? [ cur.hash ] : [],
root = fm.root(cur.hash);
while (dir && (phash = dir.phash)) {
if (fm.navHash2Elm(dir.hash).hasClass(loaded)) {
* 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(),
node = fm.navHash2Elm(curHash);
while(cur && cur.phash) {
if (hasMoreDirs[cur.phash] && !fm.navHash2Elm(cur.hash).length) {
hasMoreDirs[cur.phash].trigger('update.'+fm.namespace, { select : cur.hash });
cur = fm.file(cur.phash);
node = fm.navHash2Elm(curHash);
* Flag indicating that synchronization is currently in progress
* 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) {
autoScr = aScr === void(0)? syncTree : aScr,
loadParents = function(dir) {
var dfd = jQuery.Deferred(),
makeReq = function(cmd, h, until) {
reqs = jQuery.map(ends, function(h) {
isRoot = d? fm.isRoot(d) : false,
node = fm.navHash2Elm(h),
getPhash = function(h, dep) {
ph = (d = fm.file(h))? d.phash : false;
return getPhash(ph, --depth);
if (fm.navHash2Elm(phash).hasClass(loaded)) {
if (!node.hasClass(loaded) && (isRoot || !d || !fm.navHash2Elm(d.phash).hasClass(loaded))) {
if (isRoot || closest === getPhash(h) || closest === getPhash(h, 2)) {
baseHash = (cmd === 'tree')? h : closest;
return makeReq(cmd, h, until);
selectPages(fm.file(baseHash));
baseId = fm.navHash2Id(baseHash);
autoScr && autoScroll(baseId);
baseNode = jQuery('#'+baseId);
spinner = jQuery(fm.res('tpl', 'navspinner')).insertBefore(baseNode.children('.'+arrow));
baseNode.removeClass(collapsed);
jQuery.when.apply($, reqs)
var res = {},data, treeDirs, dirs, argLen, i;
argLen = arguments.length;
for (i = 0; i < argLen; i++) {
data = arguments[i].tree || [];
res[ends[i]] = Object.assign([], filter(data));
done= function(res, dfrd) {
if (openRoot && baseNode) {
findSubtree(baseNode.hash).show().prev(selNavdir).addClass(expanded);
autoScroll().done(checkSubdirs);
jQuery.each(res, function(endHash, dirs) {
dirs && updateTree(dirs);
selectPages(fm.file(endHash));
dirs && updateArrows(dirs, loaded);
(fm.api < 2.1) && cwdDirs.push(cwd);
if (!current.hasClass(active)) {
tree.find(selNavdir+'.'+active).removeClass(active);
current.addClass(active);