Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 18 additions & 13 deletions src/document/DocumentCommandHandlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -347,19 +347,24 @@ define(function (require, exports, module) {
_$dirtydot.css("visibility", "hidden");
}

// Set _$titleWrapper to a fixed width just large enough to accommodate _$title. This seems equivalent to what
// the browser would do automatically, but the CSS trick we use for layout requires _$titleWrapper to have a
// fixed width set on it (see the "#titlebar" CSS rule for details).
_$titleWrapper.css("width", "");
var newWidth = _$title.width();
_$titleWrapper.css("width", newWidth);

// Changing the width of the title may cause the toolbar layout to change height, which needs to resize the
// editor beneath it (toolbar changing height due to window resize is already caught by EditorManager).
var newToolbarHeight = _$titleContainerToolbar.height();
if (_lastToolbarHeight !== newToolbarHeight) {
_lastToolbarHeight = newToolbarHeight;
WorkspaceManager.recomputeLayout();
if (!Phoenix.isNativeApp) {
// In the native app the title-wrapper is display:none (the OS window titlebar
// shows the file name), so none of this layout work applies there.

// Set _$titleWrapper to a fixed width just large enough to accommodate _$title. This seems equivalent
// to what the browser would do automatically, but the CSS trick we use for layout requires
// _$titleWrapper to have a fixed width set on it (see the "#titlebar" CSS rule for details).
_$titleWrapper.css("width", "");
const newWidth = _$title.width();
_$titleWrapper.css("width", newWidth);

// Changing the width of the title may cause the toolbar layout to change height, which needs to resize
// the editor beneath it (toolbar changing height due to window resize is already caught by EditorManager).
const newToolbarHeight = _$titleContainerToolbar.height();
if (_lastToolbarHeight !== newToolbarHeight) {
_lastToolbarHeight = newToolbarHeight;
WorkspaceManager.recomputeLayout();
}
}


Expand Down
11 changes: 9 additions & 2 deletions src/extensionsIntegrated/Terminal/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -885,8 +885,15 @@ define(function (require, exports, module) {
id: "terminal-toolbar-button",
href: "#",
title: Strings.CMD_VIEW_TERMINAL
})
.insertBefore("#app-drawer-button");
});
// The profile button (added externally by phoenix-pro) must stay at the
// very bottom of the toolbar, and it may or may not exist yet at appReady.
const $profileBtn = $("#user-profile-button");
if ($profileBtn.length) {
$btn.insertBefore($profileBtn);
} else {
$btn.appendTo($("#main-toolbar .bottom-buttons"));
}

$btn.on("click", function () {
if (WorkspaceManager.isInDesignMode()) {
Expand Down
6 changes: 5 additions & 1 deletion src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1045,7 +1045,11 @@
<a id="update-notification" href="#" class="forced-hidden"></a>
</div>
<div class="bottom-buttons">
<a id="app-drawer-button" href="#"></a>
<!-- app drawer button hidden for now - need to decide a new icon as the current
one can be confused with the styles bar layout button. if bringing this back,
also uncomment its tests in MainViewManager-integ-test.js and
CentralControlBar-integ-test.js (search for app-drawer-button) -->
<!-- <a id="app-drawer-button" href="#"></a> -->

Check warning on line 1052 in src/index.html

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this commented out code.

See more on https://sonarcloud.io/project/issues?id=phcode-dev_phoenix&issues=AZ9SOxdw-c_STaj1-5tr&open=AZ9SOxdw-c_STaj1-5tr&pullRequest=3021
</div>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/styles/brackets_patterns_override.less
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ a:focus {
}

body.tauri & {
.title, .dirty-dot {
// In tauri, the window title bar shows the file name fully. so this isn't required.
display: flow-root;
.title-wrapper {
display: none;
}
}
Expand Down
41 changes: 32 additions & 9 deletions src/utils/Resizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,23 @@
$resizeShield.off("mousedown");
$resizeShield.remove();
animationRequest = null;
toggle($element);

// The shield covers the whole window, so only treat this press as
// the second click of a double click if it landed on/near the
// resizer; stray clicks elsewhere just dismiss the shield.
const buffer = 8;
const resizerOffset = $resizer.offset();
let nearResizer;
if (direction === DIRECTION_HORIZONTAL) {
nearResizer = e.pageX >= resizerOffset.left - buffer &&
e.pageX <= resizerOffset.left + $resizer.outerWidth() + buffer;
} else {
nearResizer = e.pageY >= resizerOffset.top - buffer &&
e.pageY <= resizerOffset.top + $resizer.outerHeight() + buffer;
}
if (nearResizer) {
toggle($element);
}
});
}

Expand All @@ -616,18 +632,25 @@

isResizing = false;

if (resizeStarted) {
$element.trigger(EVENT_PANEL_RESIZE_END, [elementSize]);
}

// We wait 300ms to remove the resizer container to capture a mousedown
// on the container that would account for double click
window.setTimeout(function () {
function removeShield() {

Check failure on line 635 in src/utils/Resizer.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest functions more than 4 levels deep.

See more on https://sonarcloud.io/project/issues?id=phcode-dev_phoenix&issues=AZ9SOxZG-c_STaj1-5tq&open=AZ9SOxZG-c_STaj1-5tq&pullRequest=3021
$(window.document).off("mousemove", onMouseMove);
$resizeShield.off("mousedown");
$resizeShield.remove();
animationRequest = null;
}, 300);
}

if (resizeStarted) {
$element.trigger(EVENT_PANEL_RESIZE_END, [elementSize]);
// A double click never includes a drag between its two presses,
// so after a real resize the shield isn't needed to catch a
// second click — remove it right away so it doesn't swallow
// clicks elsewhere in the window.
removeShield();
} else {
// We wait 300ms to remove the resizer container to capture a mousedown
// on the container that would account for double click
window.setTimeout(removeShield, 300);
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions test/spec/CentralControlBar-integ-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,9 @@ define(function (require, exports, module) {
}
});

// app-drawer-button is commented out in index.html for now,
// uncomment these two tests when it comes back
/*
it("should exit design mode and open the tools bottom panel when #app-drawer-button is clicked in design mode", async function () {
await enterDesignMode();
expect(WorkspaceManager.isInDesignMode()).toBe(true);
Expand All @@ -1056,6 +1059,7 @@ define(function (require, exports, module) {
"tools bottom panel to become visible", 3000);
expect(WorkspaceManager.isInDesignMode()).toBe(false);
});
*/

it("should exit design mode before mounting Find in Files bar", async function () {
await enterDesignMode();
Expand Down
12 changes: 7 additions & 5 deletions test/spec/DragTestUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,13 @@ define(function (require, exports, module) {

_fireMouse(doc, "mouseup", endX, endY, testWindow, 0);
await _awaitFrames(testWindow, 2);
// Resizer leaves a full-viewport `.resizing-container` shield in the DOM
// for 300ms after mouseup (so a trailing mousedown still registers as a
// double-click). If the next test fires its mousedown before that shield
// is removed, it lands on the shield rather than the handle and the drag
// silently no-ops. Waiting the shield out makes consecutive drags reliable.
// After a real drag Resizer removes its full-viewport `.resizing-container`
// shield immediately on mouseup, but a press+release with no effective
// movement leaves it in the DOM for 300ms (so a trailing mousedown still
// registers as a double-click). If a drag degenerates to no movement and
// the next test fires its mousedown before the shield is removed, it lands
// on the shield rather than the handle and the drag silently no-ops.
// Waiting the window out keeps consecutive drags reliable either way.
await new Promise(function (resolve) { testWindow.setTimeout(resolve, 320); });
}

Expand Down
37 changes: 37 additions & 0 deletions test/spec/MainViewManager-integ-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,35 @@ define(function (require, exports, module) {
expect(isDisplayed).toBeFalse();

});

it("should set a fixed title wrapper width in browser windows", async function () {
if(Phoenix.isNativeApp) {
return;
}
const openPromise = MainViewManager._open(MainViewManager.FIRST_PANE,
FileSystem.getFileForPath(testPath + "/test.js"));
await awaitsForDone(openPromise, "MainViewManager.doOpen");

const wrapper = testWindow.$('.title-wrapper')[0];
await awaitsFor(function () {
return parseFloat(wrapper.style.width) > 0;
}, "title wrapper to get a fixed width", 2000);
});

it("should not set a title wrapper width in tauri windows", async function () {
if(!Phoenix.isNativeApp) {
return;
}
const openPromise = MainViewManager._open(MainViewManager.FIRST_PANE,
FileSystem.getFileForPath(testPath + "/test.js"));
await awaitsForDone(openPromise, "MainViewManager.doOpen");

// In native apps, the file name is shown in the OS window title bar
// the in-app wrapper for file name stays hidden and _updateTitle skips its layout work...
const $wrapper = testWindow.$('.title-wrapper');
expect($wrapper.css("display")).toBe("none");
expect($wrapper[0].style.width).toBe("");
});
});

describe("opening and closing files", function () {
Expand Down Expand Up @@ -1153,6 +1182,9 @@ define(function (require, exports, module) {
WorkspaceManager.destroyBottomPanel("focusTestPanel");
});

// app-drawer-button is commented out in index.html for now,
// uncomment this test when it comes back
/*
it("should app-drawer-button toggle the default panel", async function () {
panel1.hide();
panel2.hide();
Expand All @@ -1170,6 +1202,7 @@ define(function (require, exports, module) {
_$("#app-drawer-button").click();
expect(defaultPanel.isVisible()).toBeFalse();
});
*/

it("should escape collapse bottom panel regardless of canBeShown", async function () {
panel1.show();
Expand Down Expand Up @@ -1416,6 +1449,9 @@ define(function (require, exports, module) {
});
});

// app-drawer-button is commented out in index.html for now,
// uncomment this describe when it comes back
/*
describe("Quick Access panel (app drawer button)", function () {
const DEFAULT_PANEL_ID = "workspace.defaultPanel";

Expand Down Expand Up @@ -1485,5 +1521,6 @@ define(function (require, exports, module) {
await CommandManager.execute(Commands.VIEW_TOGGLE_PROBLEMS);
});
});
*/
});
});
108 changes: 107 additions & 1 deletion test/spec/SidebarTabs-integ-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*
*/

/*global describe, it, expect, beforeAll, afterAll, beforeEach, awaitsFor, awaitsForDone, jsPromise */
/*global describe, it, expect, beforeAll, afterAll, beforeEach, afterEach, awaitsFor, awaitsForDone, jsPromise */

define(function (require, exports, module) {

Expand Down Expand Up @@ -586,5 +586,111 @@ define(function (require, exports, module) {
expect(prefs.size).toBe(380);
});
});

describe("Sidebar resizer double-click and drag shield", function () {

function fireMouse(target, type, x, y) {
const ev = new testWindow.MouseEvent(type, {
bubbles: true,
cancelable: true,
view: testWindow,
clientX: x,
clientY: y,
button: 0,
buttons: type === "mouseup" ? 0 : 1
});
target.dispatchEvent(ev);
}

function awaitFrames(n) {
return new Promise(function (resolve) {
let remaining = n;
function tick() {
remaining -= 1;
if (remaining <= 0) {
resolve();
return;
}
testWindow.requestAnimationFrame(tick);
}
testWindow.requestAnimationFrame(tick);
});
}

function resizerCenter() {
const rect = _$("#sidebar > .horz-resizer")[0].getBoundingClientRect();
return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
}

beforeEach(async function () {
SidebarView.show();
_$(".resizing-container").remove();
SidebarView.resize(300);
await awaitsFor(function () {
return _$("#sidebar")[0].offsetWidth === 300;
}, "sidebar to settle at baseline 300px", 2000);
});

afterEach(function () {
_$(".resizing-container").remove();
SidebarView.show();
});

it("should collapse the sidebar on resizer double click", function () {
const center = resizerCenter();
const $resizer = _$("#sidebar > .horz-resizer");

fireMouse($resizer[0], "mousedown", center.x, center.y);
fireMouse(testWindow.document, "mouseup", center.x, center.y);
const $shield = _$(".resizing-container");
expect($shield.length).toBe(1);

fireMouse($shield[0], "mousedown", center.x, center.y);
expect(SidebarView.isVisible()).toBe(false);
});

it("should not collapse the sidebar when the second press lands away from the resizer", function () {
const center = resizerCenter();
const $resizer = _$("#sidebar > .horz-resizer");

fireMouse($resizer[0], "mousedown", center.x, center.y);
fireMouse(testWindow.document, "mouseup", center.x, center.y);
const $shield = _$(".resizing-container");
expect($shield.length).toBe(1);

fireMouse($shield[0], "mousedown", center.x + 200, center.y);
expect(SidebarView.isVisible()).toBe(true);
expect(_$(".resizing-container").length).toBe(0);
});

it("should remove the shield right after a drag so a quick editor click cannot collapse", async function () {
const center = resizerCenter();
const $resizer = _$("#sidebar > .horz-resizer");

fireMouse($resizer[0], "mousedown", center.x, center.y);
await awaitFrames(1);
for (let i = 1; i <= 5; i++) {
fireMouse(testWindow.document, "mousemove", center.x + i * 10, center.y);
await awaitFrames(1);
}
fireMouse(testWindow.document, "mouseup", center.x + 50, center.y);
await awaitFrames(1);

const widthAfterDrag = _$("#sidebar")[0].offsetWidth;
expect(widthAfterDrag).toBeGreaterThan(300);

expect(_$(".resizing-container").length).toBe(0);

const edRect = _$("#editor-holder")[0].getBoundingClientRect();
const clickX = edRect.left + edRect.width / 2;
const clickY = edRect.top + edRect.height / 2;
const target = testWindow.document.elementFromPoint(clickX, clickY) || _$("#editor-holder")[0];
fireMouse(target, "mousedown", clickX, clickY);
fireMouse(target, "mouseup", clickX, clickY);

expect(SidebarView.isVisible()).toBe(true);
expect(_$("#sidebar")[0].offsetWidth).toBe(widthAfterDrag);
});
});
});
});
Loading