diff --git a/src/LiveDevelopment/LiveDevelopment.js b/src/LiveDevelopment/LiveDevelopment.js index a5733db55da..e8291a25dbe 100644 --- a/src/LiveDevelopment/LiveDevelopment.js +++ b/src/LiveDevelopment/LiveDevelopment.js @@ -501,27 +501,22 @@ define(function LiveDevelopment(require, exports, module) { /** Triggered by a document saved from the DocumentManager */ function _onDocumentSaved(event, doc) { - if (doc && Inspector.connected() && _classForDocument(doc) !== CSSDocument) { - if (agents.network && agents.network.wasURLRequested(doc.url)) { - // Reload HTML page - Inspector.Page.reload(); - - // Reload unsaved changes - _onReconnect(); - - // Set status back to active - _setStatus(STATUS_ACTIVE); - } + if (doc && Inspector.connected() && _classForDocument(doc) !== CSSDocument && + agents.network && agents.network.wasURLRequested(doc.url)) { + // Reload HTML page + Inspector.Page.reload(); + + // Reload unsaved changes + _onReconnect(); } } /** Triggered by a change in dirty flag from the DocumentManager */ function _onDirtyFlagChange(event, doc) { - if (Inspector.connected() && doc && doc.isDirty && _classForDocument(doc) !== CSSDocument) { - if (agents.network && agents.network.wasURLRequested(doc.url)) { - // Set status to out of sync - _setStatus(STATUS_OUT_OF_SYNC); - } + if (doc && Inspector.connected() && _classForDocument(doc) !== CSSDocument && + agents.network && agents.network.wasURLRequested(doc.url)) { + // Set status to out of sync if dirty. Otherwise, set it to active status. + _setStatus(doc.isDirty ? STATUS_OUT_OF_SYNC : STATUS_ACTIVE); } } diff --git a/src/command/Menus.js b/src/command/Menus.js index 21b868f5059..b618ce14ce5 100644 --- a/src/command/Menus.js +++ b/src/command/Menus.js @@ -966,7 +966,7 @@ define(function (require, exports, module) { var project_cmenu = registerContextMenu(ContextMenuIds.PROJECT_MENU); project_cmenu.addMenuItem(Commands.FILE_NEW); project_cmenu.addMenuItem(Commands.FILE_NEW_FOLDER); - project_cmenu.addMenuItem(Commands.FILE_RENAME); + project_cmenu.addMenuItem(Commands.FILE_RENAME, "F2"); var working_set_cmenu = registerContextMenu(ContextMenuIds.WORKING_SET_MENU); working_set_cmenu.addMenuItem(Commands.FILE_CLOSE); diff --git a/src/document/DocumentManager.js b/src/document/DocumentManager.js index 78f5b05cebb..39a5fea0dc9 100644 --- a/src/document/DocumentManager.js +++ b/src/document/DocumentManager.js @@ -299,6 +299,23 @@ define(function (require, exports, module) { } + /** + * Mutually exchanges the files at the indexes passed by parameters. + * @param {!number} index - old file index + * @param {!number} index - new file index + */ + function swapWorkingSetIndexes(index1, index2) { + var length = _workingSet.length - 1; + var temp; + + if (index1 >= 0 && index2 <= length && index1 >= 0 && index2 <= length) { + temp = _workingSet[index1]; + _workingSet[index1] = _workingSet[index2]; + _workingSet[index2] = temp; + } + } + + /** * Indicate that changes to currentDocument are temporary for now, and should not update the MRU * ordering of the working set. Useful for next/previous keyboard navigation (until Ctrl is released) @@ -1121,6 +1138,7 @@ define(function (require, exports, module) { exports.addListToWorkingSet = addListToWorkingSet; exports.removeFromWorkingSet = removeFromWorkingSet; exports.getNextPrevFile = getNextPrevFile; + exports.swapWorkingSetIndexes = swapWorkingSetIndexes; exports.beginDocumentNavigation = beginDocumentNavigation; exports.finalizeDocumentNavigation = finalizeDocumentNavigation; exports.closeFullEditor = closeFullEditor; @@ -1130,7 +1148,7 @@ define(function (require, exports, module) { // Setup preferences _prefs = PreferencesManager.getPreferenceStorage(PREFERENCES_CLIENT_ID); - $(exports).bind("currentDocumentChange workingSetAdd workingSetAddList workingSetRemove workingSetRemoveList fileNameChange", _savePreferences); + $(exports).bind("currentDocumentChange workingSetAdd workingSetAddList workingSetRemove workingSetRemoveList fileNameChange workingSetReorder", _savePreferences); // Performance measurements PerfUtils.createPerfMeasurement("DOCUMENT_MANAGER_GET_DOCUMENT_FOR_PATH", "DocumentManager.getDocumentForPath()"); diff --git a/src/editor/EditorManager.js b/src/editor/EditorManager.js index cad78b89af6..d4ed9d02639 100644 --- a/src/editor/EditorManager.js +++ b/src/editor/EditorManager.js @@ -614,7 +614,7 @@ define(function (require, exports, module) { } function _updateModeInfo(editor) { - $modeInfo.text(editor.getModeForSelection()); + $modeInfo.text(StatusBar.getModeDisplayString(editor.getModeForSelection())); } function _updateFileInfo(editor) { diff --git a/src/project/WorkingSetView.js b/src/project/WorkingSetView.js index 1f7c326efae..45485e0f9a9 100644 --- a/src/project/WorkingSetView.js +++ b/src/project/WorkingSetView.js @@ -23,7 +23,7 @@ /*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */ -/*global define, $ */ +/*global define, $, window */ /** * WorkingSetView generates the UI for the list of the files user is editing based on the model provided by EditorManager. @@ -37,6 +37,7 @@ define(function (require, exports, module) { var DocumentManager = require("document/DocumentManager"), CommandManager = require("command/CommandManager"), Commands = require("command/Commands"), + Menus = require("command/Menus"), EditorManager = require("editor/EditorManager"), FileViewController = require("project/FileViewController"), NativeFileSystem = require("file/NativeFileSystem").NativeFileSystem, @@ -90,6 +91,194 @@ define(function (require, exports, module) { _fireSelectionChanged(); } + /** + * Starts the drag and drop working set view reorder. + * @private + * @param {!Event} event - jQuery event + * @paran {!HTMLLIElement} $listItem - jQuery element + * @param {?bool} fromClose - true if reorder was called from the close icon + */ + function _reorderListItem(event, $listItem, fromClose) { + var $prevListItem = $listItem.prev(), + $nextListItem = $listItem.next(), + selected = $listItem.hasClass("selected"), + prevSelected = $prevListItem.hasClass("selected"), + nextSelected = $nextListItem.hasClass("selected"), + index = DocumentManager.findInWorkingSet($listItem.data(_FILE_KEY).fullPath), + height = $listItem.height(), + startPageY = event.pageY, + listItemTop = startPageY - $listItem.offset().top, + listItemBottom = $listItem.offset().top + height - startPageY, + offsetTop = $openFilesContainer.offset().top, + scrollElement = $openFilesContainer.get(0), + containerHeight = scrollElement.clientHeight, + maxScroll = scrollElement.scrollHeight - containerHeight, + hasScroll = scrollElement.scrollHeight > containerHeight, + hasBottomShadow = scrollElement.scrollHeight > scrollElement.scrollTop + containerHeight, + addBottomShadow = false, + interval = false, + moved = false; + + // Drag the List Item + function drag(e) { + var top = e.pageY - startPageY; + + // Drag if the item is not the first and moving it up or + // if the item is not the last and moving down + if (($prevListItem.length && top < 0) || ($nextListItem.length && top > 0)) { + // Reorder the list once the item is halfway to the new position + if (Math.abs(top) > height / 2) { + // If moving up, place the previows item after the moving item + if (top < 0) { + $prevListItem.insertAfter($listItem); + startPageY -= height; + top = top + height; + DocumentManager.swapWorkingSetIndexes(index, --index); + // If moving down, place the next item before the moving item + } else { + $nextListItem.insertBefore($listItem); + startPageY += height; + top = top - height; + DocumentManager.swapWorkingSetIndexes(index, ++index); + } + + // Update the selection when the previows or next element were selected + if (!selected && ((top > 0 && prevSelected) || (top < 0 && nextSelected))) { + _fireSelectionChanged(); + } + + // Update the previows and next items + $prevListItem = $listItem.prev(); + $nextListItem = $listItem.next(); + prevSelected = $prevListItem.hasClass("selected"); + nextSelected = $nextListItem.hasClass("selected"); + + // If the last item of the list was selected and the previows was moved to its location, then + // the it will show a bottom shadow even if it shouldnt because of the way the scrollHeight is + // handle with relative position. This will remove that shadow and add it on drop. + if (!addBottomShadow && !hasBottomShadow && !$nextListItem.length && prevSelected) { + ViewUtils.removeScrollerShadow($openFilesContainer[0], null); + ViewUtils.addScrollerShadow($openFilesContainer[0], null, false); + addBottomShadow = true; + } + } + // Set the top to 0 as the event probably didnt fired at the exact start/end of the list + } else { + top = 0; + } + + // Move the item + $listItem.css("top", top + "px"); + + // Update the selection position + if (selected) { + _fireSelectionChanged(); + } + + // Once the movement is greater than 3 pixels, it is assumed that the user wantes to reorder files and not open + if (!moved && Math.abs(top) > 3) { + Menus.closeAll(); + moved = true; + } + } + + function endScroll() { + window.clearInterval(interval); + interval = false; + } + + // Scroll view if the mouse is over the first or last pixels of the container + function scroll(e) { + var dir = 0; + // Mouse over the first visible pixels and moving up + if (e.pageY - listItemTop < offsetTop + 7) { + dir = -1; + // Mouse over the last visible pixels and moving down + } else if (e.pageY + listItemBottom > offsetTop + containerHeight - 7) { + dir = 1; + } + + if (dir && !interval) { + // Scroll and drag as long as needed + interval = window.setInterval(function () { + var scrollTop = $openFilesContainer.scrollTop(); + // End scroll if there isn't more to scroll + if ((dir === -1 && scrollTop <= 0) || (dir === 1 && scrollTop >= maxScroll)) { + endScroll(); + } else { + $openFilesContainer.scrollTop(scrollTop + 7 * dir); + startPageY -= 7 * dir; + drag(e); + } + }, 100); + } else if (!dir && interval) { + endScroll(); + } + } + + // Drop List Item + function drop() { + // Enable Mousewheel + window.onmousewheel = window.document.onmousewheel = null; + + // Removes the styles, placing the item in the chosen place + $listItem.removeAttr("style"); + + // End the scrolling if needed + if (interval) { + window.clearInterval(interval); + } + + // If file wasnt moved open or close it + if (!moved) { + if (!fromClose) { + FileViewController.openAndSelectDocument($listItem.data(_FILE_KEY).fullPath, FileViewController.WORKING_SET_VIEW); + } else { + CommandManager.execute(Commands.FILE_CLOSE, {file: $listItem.data(_FILE_KEY)}); + } + } else if (moved) { + if (selected) { + // Update the file selection + _fireSelectionChanged(); + ViewUtils.scrollElementIntoView($openFilesContainer, $listItem, false); + } + if (addBottomShadow) { + // Restore the shadows + ViewUtils.addScrollerShadow($openFilesContainer[0], null, true); + } + } + + // Dispatch event + $(DocumentManager).triggerHandler("workingSetReorder"); + } + + + // Only drag with the left mouse button, end the drop in other cases + if (event.which !== 1) { + drop(); + return; + } + + // Disable Mousewheel while dragging + window.onmousewheel = window.document.onmousewheel = function (e) { e.preventDefault(); }; + + // Style the element + $listItem.css("position", "relative").css("z-index", 1); + + // Envent Handlers + $openFilesContainer.on("mousemove.workingSet", function (e) { + if (hasScroll) { + scroll(e); + } + drag(e); + }); + $openFilesContainer.on("mouseup.workingSet mouseleave.workingSet", function (e) { + $openFilesContainer.off("mousemove.workingSet mouseup.workingSet mouseleave.workingSet"); + drop(); + + }); + } + /** * Updates the appearance of the list element based on the parameters provided * @private @@ -112,16 +301,14 @@ define(function (require, exports, module) { $fileStatusIcon = $("
") .prependTo(listElement) .mousedown(function (e) { + // Try to drag if that is what is wanted if not it will be the equivalent to File > Close; + // it doesn't merely remove a file from the working set + _reorderListItem(e, $(this).parent(), true); + // stopPropagation of mousedown for fileStatusIcon so the parent