Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.

Commit d1cc272

Browse files
committed
Merge pull request #3370 from adobe/nj/manual-refresh
Adds a refresh menu item
2 parents 8653151 + 811df0f commit d1cc272

4 files changed

Lines changed: 118 additions & 28 deletions

File tree

src/command/Commands.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ define(function (require, exports, module) {
5050
exports.FILE_DELETE = "file.delete";
5151
exports.FILE_INSTALL_EXTENSION = "file.installExtension";
5252
exports.FILE_EXTENSION_MANAGER = "file.extensionManager";
53+
exports.FILE_REFRESH = "file.refresh";
5354
exports.FILE_QUIT = "file.quit"; // string must MATCH string in native code (brackets_extensions)
5455

5556
// EDIT

src/command/DefaultMenus.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ define(function (require, exports, module) {
185185
project_cmenu.addMenuItem(Commands.NAVIGATE_SHOW_IN_OS);
186186
project_cmenu.addMenuDivider();
187187
project_cmenu.addMenuItem(Commands.EDIT_FIND_IN_SUBTREE);
188+
project_cmenu.addMenuDivider();
189+
project_cmenu.addMenuItem(Commands.FILE_REFRESH);
188190

189191
var working_set_cmenu = Menus.registerContextMenu(Menus.ContextMenuIds.WORKING_SET_MENU);
190192
working_set_cmenu.addMenuItem(Commands.FILE_CLOSE);

src/nls/pt-br/strings.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ define({
160160
"CMD_FILE_SAVE_ALL" : "Salvar Tudo",
161161
"CMD_LIVE_FILE_PREVIEW" : "Live Preview",
162162
"CMD_FILE_RENAME" : "Renomear",
163+
"CMD_FILE_REFRESH" : "Atualizar",
163164
"CMD_QUIT" : "Sair",
164165

165166
// Edit menu commands

src/project/ProjectManager.js

Lines changed: 114 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ define(function (require, exports, module) {
6666
FileUtils = require("file/FileUtils"),
6767
NativeFileError = require("file/NativeFileError"),
6868
Urls = require("i18n!nls/urls"),
69-
KeyEvent = require("utils/KeyEvent");
69+
KeyEvent = require("utils/KeyEvent"),
70+
Async = require("utils/Async");
7071

7172
/**
7273
* @private
@@ -136,11 +137,14 @@ define(function (require, exports, module) {
136137
* @private
137138
* Used to initialize jstree state
138139
*/
139-
var _projectInitialLoad = {
140-
previous : [], /* array of arrays containing full paths to open at each depth of the tree */
141-
id : 0, /* incrementing id */
142-
fullPathToIdMap : {} /* mapping of fullPath to tree node id attr */
143-
};
140+
var _projectInitialLoad = null;
141+
142+
/**
143+
* @private
144+
* While initially rendering the tree, stores a list of promises for folders waiting to be read.
145+
* Is null when tree is not doing its initial rendering.
146+
*/
147+
var _renderPromises = null;
144148

145149
var suppressToggleOpen = false;
146150

@@ -377,7 +381,9 @@ define(function (require, exports, module) {
377381

378382
// suppress selectionChanged event from firing by jstree select_node
379383
_suppressSelectionChange = true;
380-
_projectTree.jstree("deselect_node", current);
384+
if (current) {
385+
_projectTree.jstree("deselect_node", current);
386+
}
381387
_projectTree.jstree("select_node", target, false);
382388
_suppressSelectionChange = false;
383389

@@ -395,6 +401,43 @@ define(function (require, exports, module) {
395401
function _isInRename(element) {
396402
return ($(element).closest("li").find("input").length > 0);
397403
}
404+
405+
/**
406+
* Resolves the given deferred when all renderPromises have been resolved. This is necessary in order
407+
* to determine when iniital rendering is really finished; we don't actually get a callback from jstree
408+
* once it's handled all of its "reopen" callbacks, so we instead track all of our own async file requests
409+
* (which should be the only asynchronicity involved in rendering the tree). Since new requests might get
410+
* added in the course of recursing the tree, we can't just do a simple $.when.apply() here.
411+
*
412+
* @param {$.Deferred} the deferred to resolve when rendering is finished
413+
*/
414+
function _whenRenderedResolve(deferred) {
415+
if (_renderPromises) {
416+
_renderPromises.forEach(function (promise) {
417+
// Only listen to each promise once.
418+
if (!promise._project_listening) {
419+
promise._project_listening = true;
420+
promise.always(function () {
421+
// One of the promises is completed (either resolved or rejected;
422+
// in either case we want to move on).
423+
// Remove it from the list, then see if we have any more left.
424+
var index = _renderPromises.indexOf(promise);
425+
if (index !== -1) {
426+
_renderPromises.splice(index, 1);
427+
}
428+
if (_renderPromises.length === 0) {
429+
// All done.
430+
deferred.resolve();
431+
_renderPromises = null;
432+
} else {
433+
// Add listeners to any new promises that have shown up.
434+
_whenRenderedResolve(deferred);
435+
}
436+
});
437+
}
438+
});
439+
}
440+
}
398441

399442
/**
400443
* @private
@@ -406,6 +449,8 @@ define(function (require, exports, module) {
406449
function _renderTree(treeDataProvider) {
407450
var result = new $.Deferred();
408451

452+
_renderPromises = [];
453+
409454
// For #1542, make sure the tree is scrolled to the top before refreshing.
410455
// If we try to do this later (e.g. after the tree has been refreshed), it
411456
// doesn't seem to work properly.
@@ -504,8 +549,8 @@ define(function (require, exports, module) {
504549
_projectTree.jstree("reload_nodes", false);
505550
}
506551
if (_projectInitialLoad.previous.length === 0) {
507-
// resolve after all paths are opened
508-
result.resolve();
552+
// resolve after all paths are opened and fully rendered
553+
_whenRenderedResolve(result);
509554
}
510555
}
511556
).bind(
@@ -583,7 +628,7 @@ define(function (require, exports, module) {
583628
$projectTreeContainer.show();
584629
});
585630

586-
return result.promise();
631+
return Async.withTimeout(result.promise(), 1000);
587632
}
588633

589634
/**
@@ -658,7 +703,7 @@ define(function (require, exports, module) {
658703
* @param {function(Array)} jsTreeCallback jsTree callback to provide children to
659704
*/
660705
function _treeDataProvider(treeNode, jsTreeCallback) {
661-
var dirEntry, isProjectRoot = false;
706+
var dirEntry, isProjectRoot = false, deferred = new $.Deferred();
662707

663708
function processEntries(entries) {
664709
var subtreeJSON = _convertEntriesToJSON(entries),
@@ -691,6 +736,8 @@ define(function (require, exports, module) {
691736
treeNode.trigger("open_node.jstree");
692737
}
693738
}
739+
740+
deferred.resolve();
694741
}
695742

696743
if (treeNode === -1) {
@@ -701,6 +748,10 @@ define(function (require, exports, module) {
701748
// All other nodes: the DirectoryEntry is saved as jQ data in the tree (by _convertEntriesToJSON())
702749
dirEntry = treeNode.data("entry");
703750
}
751+
752+
if (_renderPromises) {
753+
_renderPromises.push(deferred.promise());
754+
}
704755

705756
// Fetch dirEntry's contents
706757
dirEntry.createReader().readEntries(
@@ -720,6 +771,8 @@ define(function (require, exports, module) {
720771
error.name
721772
)
722773
);
774+
// Reject the render promise so we can move on.
775+
deferred.reject();
723776
}
724777
}
725778
);
@@ -780,25 +833,34 @@ define(function (require, exports, module) {
780833
*
781834
* @param {string} rootPath Absolute path to the root folder of the project.
782835
* If rootPath is undefined or null, the last open project will be restored.
836+
* @param {bool} isUpdating Indicates if it's just an update attempt to the
837+
* tree or if another project is being loaded.
783838
* @return {$.Promise} A promise object that will be resolved when the
784839
* project is loaded and tree is rendered, or rejected if the project path
785840
* fails to load.
786841
*/
787-
function _loadProject(rootPath) {
788-
if (_projectRoot && _projectRoot.fullPath === rootPath + "/") {
789-
return (new $.Deferred()).resolve().promise();
790-
}
791-
if (_projectRoot) {
792-
// close current project
793-
$(exports).triggerHandler("beforeProjectClose", _projectRoot);
794-
}
795-
796-
// close all the old files
797-
DocumentManager.closeAll();
798-
799-
// reset tree node id's
800-
_projectInitialLoad.id = 0;
801842

843+
function _loadProject(rootPath, isUpdating) {
844+
if (!isUpdating) {
845+
if (_projectRoot && _projectRoot.fullPath === rootPath + "/") {
846+
return (new $.Deferred()).resolve().promise();
847+
}
848+
if (_projectRoot) {
849+
// close current project
850+
$(exports).triggerHandler("beforeProjectClose", _projectRoot);
851+
}
852+
853+
// close all the old files
854+
DocumentManager.closeAll();
855+
}
856+
857+
// Clear project path map
858+
_projectInitialLoad = {
859+
previous : [], /* array of arrays containing full paths to open at each depth of the tree */
860+
id : 0, /* incrementing id */
861+
fullPathToIdMap : {} /* mapping of fullPath to tree node id attr */
862+
};
863+
802864
var result = new $.Deferred(),
803865
resultRenderTree;
804866

@@ -838,7 +900,7 @@ define(function (require, exports, module) {
838900
// immediate children, and so on.
839901
resultRenderTree = _renderTree(_treeDataProvider);
840902

841-
resultRenderTree.done(function () {
903+
resultRenderTree.always(function () {
842904
if (projectRootChanged) {
843905
// Allow asynchronous event handlers to finish before resolving result by collecting promises from them
844906
var promises = [];
@@ -884,7 +946,6 @@ define(function (require, exports, module) {
884946
return result.promise();
885947
}
886948

887-
888949
/**
889950
* Finds the tree node corresponding to the given file/folder (rejected if the path lies
890951
* outside the project, or if it doesn't exist).
@@ -947,6 +1008,29 @@ define(function (require, exports, module) {
9471008
return result.promise();
9481009
}
9491010

1011+
/**
1012+
* Reloads the project's file tree
1013+
* @return {$.Promise} A promise object that will be resolved when the
1014+
* project tree is reloaded, or rejected if the project path
1015+
* fails to reload.
1016+
*/
1017+
function refreshFileTree() {
1018+
var selectedEntry;
1019+
if (_lastSelected) {
1020+
selectedEntry = _lastSelected.data("entry");
1021+
}
1022+
_lastSelected = null;
1023+
1024+
return _loadProject(getProjectRoot().fullPath, true)
1025+
.done(function () {
1026+
if (selectedEntry) {
1027+
_findTreeNode(selectedEntry).done(function (node) {
1028+
_forceSelection(null, node);
1029+
});
1030+
}
1031+
});
1032+
}
1033+
9501034
/**
9511035
* Expands tree nodes to show the given file or folder and selects it. Silently no-ops if the
9521036
* path lies outside the project, or if it doesn't exist.
@@ -985,7 +1069,7 @@ define(function (require, exports, module) {
9851069
.done(function () {
9861070
if (path) {
9871071
// use specified path
988-
_loadProject(path).pipe(result.resolve, result.reject);
1072+
_loadProject(path, false).pipe(result.resolve, result.reject);
9891073
} else {
9901074
// Pop up a folder browse dialog
9911075
NativeFileSystem.showOpenDialog(false, true, Strings.CHOOSE_FOLDER, _projectRoot.fullPath, null,
@@ -1489,6 +1573,7 @@ define(function (require, exports, module) {
14891573
// Commands
14901574
CommandManager.register(Strings.CMD_OPEN_FOLDER, Commands.FILE_OPEN_FOLDER, openProject);
14911575
CommandManager.register(Strings.CMD_PROJECT_SETTINGS, Commands.FILE_PROJECT_SETTINGS, _projectSettings);
1576+
CommandManager.register(Strings.CMD_FILE_REFRESH, Commands.FILE_REFRESH, refreshFileTree);
14921577

14931578
// Define public API
14941579
exports.getProjectRoot = getProjectRoot;
@@ -1507,4 +1592,5 @@ define(function (require, exports, module) {
15071592
exports.deleteItem = deleteItem;
15081593
exports.forceFinishRename = forceFinishRename;
15091594
exports.showInTree = showInTree;
1595+
exports.refreshFileTree = refreshFileTree;
15101596
});

0 commit comments

Comments
 (0)