Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Bug 426407 - New File/Folder commands should create a file/folder imm…
…ediately and allow user to rename it

- Extended implementation to top level folders
- No longer immediately creating file/folder. Rather creating a place holder dom node and prompting for name of file/folder first. This greatly simplifies the implementation and allows the user to cancel the creation by pressing "ESC".
- Refactored uiutils.js->getUserText() to take an options object and modified callers. Also removed unused promptMessage parameter and added insertAsChild option.

--Signed-off-by: Elijah El-Haddad <elijahe@ca.ibm.com>
  • Loading branch information
elijahe committed Jan 27, 2014
1 parent 4481169 commit 327c9ba
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 108 deletions.
15 changes: 0 additions & 15 deletions bundles/org.eclipse.orion.client.core/web/orion/fileClient.js
Expand Up @@ -342,21 +342,6 @@ define(['i18n!orion/navigate/nls/messages', "orion/Deferred", "orion/i18nUtil"],
});

},

/**
* @return {Boolean} this instance's renameInProgress flag
*/
getRenameInProgress: function() {
return this._renameInProgress;
},

/**
* Sets this fileClient's renameInProgress flag.
* @param {Boolean} renameInProgress
*/
setRenameInProgress: function(renameInProgress) {
this._renameInProgress = renameInProgress;
},

/**
* Copies a file or directory.
Expand Down
Expand Up @@ -177,7 +177,14 @@ define([
}
}
}
mUIUtils.getUserText(id, target, true, text, doChange, null, null, ""); //$NON-NLS-0$

mUIUtils.getUserText({
id: id,
refNode: target,
shouldHideRefNode: true,
initialText: text,
onComplete: doChange
});
}
});
}
Expand Down
Expand Up @@ -68,7 +68,7 @@ exports.Explorer = (function() {
}
},

makeNewItemPlaceHolder: function(item, domId, column_no) {
makeNewItemPlaceHolder: function(item, domId, column_no, insertAfter) {
// we want to popup the name prompt underneath the parent item.
var refNode = this.getRow(item);
var tempNode;
Expand All @@ -88,7 +88,17 @@ exports.Explorer = (function() {
var td = document.createElement("td"); //$NON-NLS-0$
td.id = domId+"placeHolderCol"; //$NON-NLS-0$
tr.appendChild(td);
refNode.appendChild(tr);
if (insertAfter) {
// insert tr after refNode, i.e. right before refNode's nextSibling in the parent
var parentNode = refNode.parentNode;
var nextSibling = refNode.nextSibling;
parentNode.insertBefore(tr, nextSibling);

var parentIndentation = parseInt(refNode.firstChild.style.paddingLeft); //refNode is a <tr>, we want the indentation of its <td>
td.style.paddingLeft = (this.myTree.getIndent() + parentIndentation) + "px";
} else {
refNode.appendChild(tr);
}
tempNode = lib.node(domId+"placeHolderRow"); //$NON-NLS-0$
refNode = lib.node(domId+"placeHolderCol"); //$NON-NLS-0$
if (tempNode && refNode) {
Expand Down
173 changes: 97 additions & 76 deletions bundles/org.eclipse.orion.client.ui/web/orion/fileCommands.js
Expand Up @@ -174,27 +174,45 @@ define(['i18n!orion/navigate/nls/messages', 'require', 'orion/webui/littlelib',

function getNewItemName(explorer, item, domId, defaultName, onDone) {
var refNode, name, tempNode;
if (item.Location === explorer.treeRoot.Location) {
refNode = lib.node(domId);
var shouldHideRefNode = true;
var insertAsChild = false;

var nodes = explorer.makeNewItemPlaceHolder(item, domId, null, true);
if (nodes) {
refNode = nodes.refNode;
tempNode = nodes.tempNode;
shouldHideRefNode = false;
insertAsChild = true;
} else {
var nodes = explorer.makeNewItemPlaceHolder(item, domId);
if (nodes) {
refNode = nodes.refNode;
tempNode = nodes.tempNode;
} else {
refNode = lib.node(domId);
}
refNode = lib.node(domId);
}

if (refNode) {
mUIUtils.getUserText(domId+"EditBox", refNode, false, defaultName, //$NON-NLS-0$
function(name) {
if (name) {
if (tempNode && tempNode.parentNode) {
tempNode.parentNode.removeChild(tempNode);
}
onDone(name);
}
});
var done = function(name) {
if (name) {
onDone(name);
}
};
var destroy = function() {
try {
if (tempNode && tempNode.parentNode) {
tempNode.parentNode.removeChild(tempNode);
}
} catch (err) {
// tempNode already removed, do nothing
}
};

mUIUtils.getUserText({
id: domId+"EditBox", //$NON-NLS-0$
refNode: refNode,
shouldHideRefNode: shouldHideRefNode,
initialText: defaultName,
onComplete: done,
onEditDestroy: destroy,
isInitialValid: true,
insertAsChild: insertAsChild
});
} else {
name = window.prompt(defaultName);
if (name) {
Expand Down Expand Up @@ -586,12 +604,14 @@ define(['i18n!orion/navigate/nls/messages', 'require', 'orion/webui/littlelib',
return;
}

var resetRenameFlag = function() {
fileClient.setRenameInProgress(false);
};
fileClient.setRenameInProgress(true);

mUIUtils.getUserText(id, refNode, true, item.Name, doMove.bind(null, item), resetRenameFlag, null, item.Directory ? "" : "."); //$NON-NLS-1$ //$NON-NLS-0$
mUIUtils.getUserText({
id: id,
refNode: refNode,
shouldHideRefNode: true,
initialText: item.Name,
onComplete: doMove.bind(null, item),
selectTo: item.Directory ? "" : "." //$NON-NLS-1$ //$NON-NLS-0$
});
};

var renameCommand = new mCommands.Command({
Expand Down Expand Up @@ -760,65 +780,67 @@ define(['i18n!orion/navigate/nls/messages', 'require', 'orion/webui/littlelib',
}
});
commandService.addCommand(downloadCommand);

function createUniqueNameArtifact(parentItem, prefix, createFunction) {
// get the list of files that already exists in the selected directory and ensure
// that the new file's initial name is unique within that directory
var location = parentItem.ChildrenLocation;
progressService.progress(fileClient.fetchChildren(location), messages["Fetching children of "] + parentItem.Name).then( //$NON-NLS-0$
function(children) {
var attempt = 0;
var uniqueName = prefix;

// find a unique name for the new artifact
var possiblyCollidingNames = children.filter(function(child){
return 0 === child.Name.indexOf(prefix);
}).map(function(child){
return child.Name;
});

while (-1 !== possiblyCollidingNames.indexOf(uniqueName)){
attempt++;
uniqueName = prefix.concat(" (").concat(attempt).concat(")"); //$NON-NLS-1$ //$NON-NLS-0$
}

// create the artifact
createFunction(uniqueName);
},
errorHandler);
}

/**
* Creates a new file or folder as a child of the specified parentItem.
*/
function createNewArtifact(defaultName, parentItem, isDirectory) {
function createNewArtifact(namePrefix, parentItem, isDirectory) {
var createFunction = function(name) {
if (name) {
var deferred = isDirectory ? fileClient.createFolder(parentItem.Location, name) : fileClient.createFile(parentItem.Location, name);
var location = parentItem.Location;
var functionName = isDirectory ? "createFolder" : "createFile";
var deferred = fileClient[functionName](location, name);
progressService.showWhile(deferred, i18nUtil.formatMessage(messages["Creating ${0}"], name)).then(
function(newArtifact) {
dispatchModelEvent({ type: "create", parent: parentItem, newValue: newArtifact }); //$NON-NLS-0$

var createEventListener = function(event){
var newValue = event.newValue;
editAndRename(newValue, null);
explorer.sidebarNavInputManager.removeEventListener("create", createEventListener); //$NON-NLS-0$
};

if (explorer.sidebarNavInputManager) {
// wait for explorer.sidebarNavInputManager to signal that the file has been created
explorer.sidebarNavInputManager.addEventListener("create", createEventListener); //$NON-NLS-0$
}
},
errorHandler);
}
};

// get the list of files that already exists in the selected directory and ensure
// that the new file's initial name is unique within that directory
progressService.progress(fileClient.fetchChildren(parentItem.ChildrenLocation), messages["Fetching children of "] + parentItem.Name).then( //$NON-NLS-0$
function(children) {
var attempt = 0;
var uniqueName = defaultName;
var possibleCollidingNames = [];

// find a unique name for the new artifact
children.forEach(function(child){
var childName = child.Name;
if (0 === childName.indexOf(uniqueName)) {
if (uniqueName.length === childName.length) {
// uniqueName matches child.Name exactly, modify uniqueName
// no need to stash childName away as a possible collision since
// uniqueName will be modified and never again equal to it
do {
attempt++;
uniqueName = defaultName + " (" + attempt + ")"; //$NON-NLS-1$ //$NON-NLS-0$
} while (-1 !== possibleCollidingNames.indexOf(uniqueName));
} else {
// uniqueName matches the beginning of child.Name
// stash child.Name away as a possible collision
possibleCollidingNames.push(childName);
}
}
});

// create the artifact
createFunction(uniqueName);
},
errorHandler);
createUniqueNameArtifact(parentItem, namePrefix, function(uniqueName){
getNewItemName(explorer, parentItem, explorer.getRow(parentItem), uniqueName, function(name) {
createFunction(name);
});
});
}

var getParentItem = function(selections, items){
var item = getTargetFolder(selections);
if (!item) {
item = explorer.treeRoot;
if (item.Project) {
item = item.children[0];
}
}
return item;
};

var newFileCommand = new mCommands.Command({
Expand All @@ -829,7 +851,7 @@ define(['i18n!orion/navigate/nls/messages', 'require', 'orion/webui/littlelib',
callback: function(data) {
// Check selection service first, then use the provided item
explorer.selection.getSelections(function(selections) {
var item = getTargetFolder(selections) || getTargetFolder(data.items);
var item = getParentItem(selections);
createNewArtifact(messages["New File"], item, false);
});
},
Expand All @@ -845,7 +867,7 @@ define(['i18n!orion/navigate/nls/messages', 'require', 'orion/webui/littlelib',
callback: function(data) {
// Check selection service first, then use the provided item
explorer.selection.getSelections(function(selections) {
var item = getTargetFolder(selections) || getTargetFolder(data.items);
var item = getParentItem(selections);
createNewArtifact(messages["New Folder"], item, true);
});
},
Expand Down Expand Up @@ -896,13 +918,12 @@ define(['i18n!orion/navigate/nls/messages', 'require', 'orion/webui/littlelib',
newFolderCommand.callback(data);
} else {
item = forceSingleItem(data.items);
if (data.parameters && data.parameters.valueFor('name')) { //$NON-NLS-0$
createProject(explorer, fileClient, progressService, data.parameters.valueFor('name')); //$NON-NLS-0$
} else {
getNewItemName(explorer, item, data.domNode.id, messages['New Folder'], function(name) {
var defaultName = messages['New Folder']; //$NON-NLS-0$
createUniqueNameArtifact(item, defaultName, function(uniqueName){
getNewItemName(explorer, item, explorer.getRow(item), uniqueName, function(name) {
createProject(explorer, fileClient, progressService, name);
});
}
});
}
});
},
Expand Down
Expand Up @@ -532,8 +532,7 @@ define([
editor.getModel().addEventListener("Changing", this._changingListener = this.onChanging.bind(this)); //$NON-NLS-0$
}
if (!noSetInput) {
var noFocus = this.fileClient.getRenameInProgress(); // don't switch focus to editor if a file or folder rename is currently in progress
editor.setInput(title, null, contents, undefined, noFocus);
editor.setInput(title, null, contents);
}
this._unsavedChanges = [];
this.processParameters(input);
Expand Down
38 changes: 26 additions & 12 deletions bundles/org.eclipse.orion.client.ui/web/orion/uiUtils.js
Expand Up @@ -108,18 +108,28 @@ define(['orion/webui/littlelib'], function(lib) {
/**
* @name orion.uiUtils.getUserText
* @function
* @param {String} id
* @param {Element} refNode
* @param {Boolean} shouldHideRefNode
* @param {String} initialText
* @param {Function} onComplete
* @param {Function} onEditDestroy
* @param {String} promptMessage
* @param {String} selectTo
* @param {Boolean} isInitialValid
* @param {Object} options The options object
* @param {String} options.id
* @param {Element} options.refNode
* @param {Boolean} options.shouldHideRefNode
* @param {String} options.initialText
* @param {Function} options.onComplete
* @param {Function} options.onEditDestroy
* @param {String} options.selectTo
* @param {Boolean} options.isInitialValid
* @param {Boolean} options.insertAsChild
*/
function getUserText(id, refNode, shouldHideRefNode, initialText, onComplete, onEditDestroy, promptMessage, selectTo, isInitialValid) {
/** @return {Function} function(event) */
function getUserText(options) {
var id = options.id;
var refNode = options.refNode;
var shouldHideRefNode = options.shouldHideRefNode;
var initialText = options.initialText;
var onComplete = options.onComplete;
var onEditDestroy = options.onEditDestroy;
var selectTo = options.selectTo;
var isInitialValid = options.isInitialValid;
var insertAsChild = options.insertAsChild;

var done = false;
var handler = function(isKeyEvent) {
return function(event) {
Expand Down Expand Up @@ -170,7 +180,11 @@ define(['orion/webui/littlelib'], function(lib) {
var editBox = document.createElement("input"); //$NON-NLS-0$
editBox.id = id;
editBox.value = initialText || "";
refNode.parentNode.insertBefore(editBox, refNode.nextSibling);
if (insertAsChild) {
refNode.appendChild(editBox);
} else {
refNode.parentNode.insertBefore(editBox, refNode.nextSibling);
}
editBox.classList.add("userEditBoxPrompt"); //$NON-NLS-0$
if (shouldHideRefNode) {
refNode.style.display = "none"; //$NON-NLS-0$
Expand Down
Expand Up @@ -319,6 +319,13 @@ define(['i18n!orion/nls/messages', 'orion/webui/littlelib'], function(messages,
if(this._onCollapse){
this._onCollapse(row._item);
}
},

/**
* Returns this tree's indentation increment
*/
getIndent: function() {
return this._indent;
}
}; // end prototype
TableTree.prototype.constructor = TableTree;
Expand Down

0 comments on commit 327c9ba

Please sign in to comment.