From 1cb3703c73b94cb7b301203c29012da0c3e7eead Mon Sep 17 00:00:00 2001 From: nao-pon Date: Sat, 13 May 2017 02:05:24 +0900 Subject: [PATCH] [ui:tree] fix #1999 split display of many directories --- css/navbar.css | 12 + js/commands/restore.js | 1 + js/elFinder.js | 38 ++- js/elFinder.options.js | 3 + js/i18n/elfinder.LANG.js | 2 + js/i18n/elfinder.en.js | 4 +- js/i18n/elfinder.jp.js | 4 +- js/ui/places.js | 3 + js/ui/tree.js | 617 ++++++++++++++++++++++++++------------- 9 files changed, 461 insertions(+), 223 deletions(-) diff --git a/css/navbar.css b/css/navbar.css index 9e597ac778..f06a2413df 100644 --- a/css/navbar.css +++ b/css/navbar.css @@ -180,6 +180,18 @@ opacity: .5; filter:Alpha(Opacity=50); } +/* pager button */ +.elfinder-navbar-pager { + width: 100%; + box-sizing: border-box; + padding-top: 3px; + padding-bottom: 3px; +} +.elfinder-touch .elfinder-navbar-pager { + padding-top: 10x; + padding-bottom: 10px; +} + .elfinder-places { border: none; margin: 0; diff --git a/js/commands/restore.js b/js/commands/restore.js index 6f89d2ce05..0d3aae9e46 100644 --- a/js/commands/restore.js +++ b/js/commands/restore.js @@ -36,6 +36,7 @@ elFinder.prototype.commands.restore = function() { items = items.concat(r.files); } }); + fm.cache(items); getFilesRecursively(items).done(function(res) { results = results.concat(res); dfd.resolve(results); diff --git a/js/elFinder.js b/js/elFinder.js index 4347ab9a26..036fa06795 100644 --- a/js/elFinder.js +++ b/js/elFinder.js @@ -1622,7 +1622,12 @@ var elFinder = function(node, opts) { done = function(data) { data.warning && self.error(data.warning); - isOpen && open(data); + if (isOpen) { + open(data); + } else { + cache(data.files || []); + cache(data.tree || []); + } self.lazy(function() { // fire some event to update cache/ui @@ -1836,17 +1841,8 @@ var elFinder = function(node, opts) { return dfrd.reject(['errMaxTargets', self.maxTargets]); } - if (defdone) { - dfrd.done(done); - } else if (cmd === 'open'){ - dfrd.done(function(data) { - var cwd = data.cwd.hash; - cache(data.files); - if (!files[cwd]) { - cache([data.cwd]); - } - }) - } + defdone && dfrd.done(done); + if (notify.type && notify.cnt) { if (cancel) { notify.cancel = dfrd; @@ -1968,6 +1964,20 @@ var elFinder = function(node, opts) { 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); + }; + /** * Compare current files cache with new files and return diff * @@ -3256,9 +3266,6 @@ var elFinder = function(node, opts) { self.dialog(''+self.i18n(e.data.error), opts); }) - .bind('tree parents', function(e) { - cache(e.data.tree || []); - }) .bind('tmb', function(e) { $.each(e.data.images||[], function(hash, tmb) { if (files[hash]) { @@ -3319,6 +3326,7 @@ var elFinder = function(node, opts) { }) .bind('searchend', function() { self.searchStatus.state = 0; + self.searchStatus.ininc = false; self.searchStatus.mixed = false; }) diff --git a/js/elFinder.options.js b/js/elFinder.options.js index d895f4043b..b2f8fe5914 100644 --- a/js/elFinder.options.js +++ b/js/elFinder.options.js @@ -489,6 +489,9 @@ elFinder.prototype._options = { openCwdOnOpen : true, // auto load current dir parents 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 : 3, // Number of max simultaneous processing directory of subdirs diff --git a/js/i18n/elfinder.LANG.js b/js/i18n/elfinder.LANG.js index 100730d0d6..05a3c499fa 100644 --- a/js/i18n/elfinder.LANG.js +++ b/js/i18n/elfinder.LANG.js @@ -180,6 +180,8 @@ '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 /******************************** notifications ********************************/ 'ntfopen' : 'Open folder', diff --git a/js/i18n/elfinder.en.js b/js/i18n/elfinder.en.js index 5c2800a1e7..ee7a62ab80 100644 --- a/js/i18n/elfinder.en.js +++ b/js/i18n/elfinder.en.js @@ -1,7 +1,7 @@ /** * English translation * @author Troex Nevelin - * @version 2017-05-02 + * @version 2017-05-11 */ // elfinder.en.js is integrated into elfinder.(full|min).js by jake build if (typeof elFinder === 'function' && elFinder.prototype.i18) { @@ -166,6 +166,8 @@ if (typeof elFinder === 'function' && elFinder.prototype.i18) { '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 /******************************** notifications ********************************/ 'ntfopen' : 'Open folder', diff --git a/js/i18n/elfinder.jp.js b/js/i18n/elfinder.jp.js index bdcfb1d1d1..e07885a483 100644 --- a/js/i18n/elfinder.jp.js +++ b/js/i18n/elfinder.jp.js @@ -2,7 +2,7 @@ * Japanese translation * @author Tomoaki Yoshida * @author Naoki Sawada - * @version 2017-05-02 + * @version 2017-05-11 */ (function(root, factory) { if (typeof define === 'function' && define.amd) { @@ -174,6 +174,8 @@ 'btnBackup' : 'バックアップ', // fromv2.1 added 28.11.2015 'btnRename' : 'リネーム', // from v2.1.24 added 6.4.2017 'btnRenameAll' : 'リネーム(全て)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : '前へ ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : '次へ ($1/$2)', // from v2.1.24 added 11.5.2017 /******************************** notifications ********************************/ 'ntfopen' : 'フォルダーを開いています', diff --git a/js/ui/places.js b/js/ui/places.js index 2a151ca90c..c3006b205c 100644 --- a/js/ui/places.js +++ b/js/ui/places.js @@ -481,6 +481,9 @@ $.fn.elfinderplaces = function(fm, opts) { }) .done(function(data) { var exists = {}; + + data.files && fm.cache(data.files); + $.each(data.files, function(i, f) { var hash = f.hash; exists[hash] = f; diff --git a/js/ui/tree.js b/js/ui/tree.js index df1592c5cd..92d0881bef 100644 --- a/js/ui/tree.js +++ b/js/ui/tree.js @@ -365,6 +365,13 @@ $.fn.elfindertree = function(fm, opts) { */ stpl = fm.res('tpl', 'symlink'), + /** + * Directory hashes that has more pages + * + * @type Object + */ + hasMoreDirs = {}, + /** * Html template replacement methods * @@ -462,7 +469,7 @@ $.fn.elfindertree = function(fm, opts) { } node = node.next(); } - return $(''); + return subtree.children('button.elfinder-navbar-pager-next'); }, /** @@ -477,9 +484,163 @@ $.fn.elfindertree = function(fm, opts) { i = length, tgts = $(), done = {}, - dir, html, parent, sibling, init, atonce = {}, base, node; - - var firstVol = true; // check for netmount volume + 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 = $.map(dirs, function(d) { + if (data.removed.indexOf(d.hash) === -1) { + return d; + } else { + changed = true; + return null; + } + }); + } + + if (data.added && data.added.length) { + dirs = dirs.concat($.map(data.added, function(d) { + if (hashes[d.hash] === void(0)) { + changed = true; + return d; + } else { + return null; + } + })); + } + 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 = $('