Skip to content
Merged
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
46 changes: 41 additions & 5 deletions src/LiveDevelopment/BrowserScripts/RemoteFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1147,6 +1147,9 @@ function RemoteFunctions(config = {}) {

NodeMoreOptionsBox.prototype = {
_registerDragDrop: function() {
// disable dragging on all elements and then enable it on the current element
const allElements = document.querySelectorAll('[data-brackets-id]');
allElements.forEach(el => el.setAttribute("draggable", false));
this.element.setAttribute("draggable", true);

this.element.addEventListener("dragstart", (event) => {
Expand Down Expand Up @@ -3006,6 +3009,8 @@ function RemoteFunctions(config = {}) {
// Make the element editable
element.setAttribute("contenteditable", "true");
element.focus();
// to compare with the new text content, if same we don't make any changes in the editor area
const oldContent = element.textContent;

// Move cursor to end if no existing selection
const selection = window.getSelection();
Expand All @@ -3015,19 +3020,46 @@ function RemoteFunctions(config = {}) {

dismissUIAndCleanupState();

// flag to check if escape is pressed, if pressed we prevent onBlur from handling it as keydown already handles
let isEscapePressed = false;

function onBlur() {
finishEditing(element);
// Small delay so that keydown can handle things first
setTimeout(() => {
if (isEscapePressed) {
isEscapePressed = false;
finishEditingCleanup(element);
return;
}

const newContent = element.textContent;
if (oldContent !== newContent) {
finishEditing(element);
} else { // if same content, we just cleanup things
finishEditingCleanup(element);
}
}, 10);
}

function onKeyDown(event) {
if (event.key === "Escape") {
isEscapePressed = true;
// Cancel editing
event.preventDefault();
finishEditing(element, false); // false means that the edit operation was cancelled
const newContent = element.textContent;
if (oldContent !== newContent) {
finishEditing(element, false); // false means that the edit operation was cancelled
} else { // no content change we can avoid sending details to the editor
finishEditingCleanup(element);
}
} else if (event.key === "Enter" && !event.shiftKey) {
isEscapePressed = false;
// Finish editing on Enter (unless Shift is held)
event.preventDefault();
finishEditing(element);
} else if ((event.key === " " || event.key === "Spacebar") && element.tagName.toLowerCase() === 'button') {
event.preventDefault();
document.execCommand("insertText", false, " ");
}
}

Expand All @@ -3041,9 +3073,7 @@ function RemoteFunctions(config = {}) {
};
}

// Function to finish editing and apply changes
// isEditSuccessful: this is a boolean value, defaults to true. false only when the edit operation is cancelled
function finishEditing(element, isEditSuccessful = true) {
function finishEditingCleanup(element) {
if (!isElementEditable(element) || !element.hasAttribute("contenteditable")) {
return;
}
Expand All @@ -3058,6 +3088,12 @@ function RemoteFunctions(config = {}) {
element.removeEventListener("keydown", element._editListeners.keydown);
delete element._editListeners;
}
}

// Function to finish editing and apply changes
// isEditSuccessful: this is a boolean value, defaults to true. false only when the edit operation is cancelled
function finishEditing(element, isEditSuccessful = true) {
finishEditingCleanup(element);

const tagId = element.getAttribute("data-brackets-id");
window._Brackets_MessageBroker.send({
Expand Down
129 changes: 0 additions & 129 deletions src/LiveDevelopment/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,122 +273,6 @@ define(function main(require, exports, module) {
return false;
}

let $livePreviewPanel = null; // stores the live preview panel, need this as overlay is appended inside this
let $overlayContainer = null; // the overlay container
let shouldShowSyncErrorOverlay = true; // once user closes the overlay we don't show them again
let shouldShowConnectingOverlay = true;
let connectingOverlayTimer = null; // this is needed as we show the connecting overlay after 3s
let connectingOverlayTimeDuration = 3000;

/**
* this function is responsible to check whether to show the overlay or not and how it should be shown
* because if user has closed the overlay manually, we don't show it again
* secondly, for connecting overlay we show that after a 3s timer, but sync error overlay is shown immediately
* @param {String} textMessage - the text that is written inside the overlay
* @param {Number} status - 1 for connect, 4 for sync error but we match it using MultiBrowserLiveDev
*/
function _handleOverlay(textMessage, status) {
if (!$livePreviewPanel) {
$livePreviewPanel = $("#panel-live-preview");
}

// remove any existing overlay & timer
_hideOverlay();

// to not show the overlays if user has already closed it before
if(status === MultiBrowserLiveDev.STATUS_CONNECTING && !shouldShowConnectingOverlay) { return; }
if(status === MultiBrowserLiveDev.STATUS_SYNC_ERROR && !shouldShowSyncErrorOverlay) { return; }

// for connecting status, we delay showing the overlay by 3 seconds
if(status === MultiBrowserLiveDev.STATUS_CONNECTING) {
connectingOverlayTimer = setTimeout(() => {
_createAndShowOverlay(textMessage, status);
connectingOverlayTimer = null;
}, connectingOverlayTimeDuration);
return;
}

// for sync error status, show immediately
_createAndShowOverlay(textMessage, status);
}

/**
* this function is responsible to create & show the overlay.
* so overlay is shown when the live preview is connecting or live preview stopped because of some syntax error
* @param {String} textMessage - the text that is written inside the overlay
* @param {Number} status - 1 for connect, 4 for sync error but we match it using MultiBrowserLiveDev
*/
function _createAndShowOverlay(textMessage, status) {
if (!$livePreviewPanel) {
$livePreviewPanel = $("#panel-live-preview");
}

// create the overlay element
// styled inside the 'src/extensionsIntegrated/Phoenix-live-preview/live-preview.css'
$overlayContainer = $("<div>").addClass("live-preview-status-overlay"); // the wrapper for overlay element
const $message = $("<div>").addClass("live-preview-overlay-message").text(textMessage);

// the close button at the right end of the overlay
const $close = $("<div>").addClass("live-preview-overlay-close")
.attr("title", Strings.LIVE_PREVIEW_HIDE_OVERLAY)
.on('click', () => {
if(status === MultiBrowserLiveDev.STATUS_CONNECTING) {
shouldShowConnectingOverlay = false;
} else if(status === MultiBrowserLiveDev.STATUS_SYNC_ERROR) {
shouldShowSyncErrorOverlay = false;
}
_hideOverlay();
});
const $closeIcon = $("<i>").addClass("fas fa-times");

$close.append($closeIcon);
$overlayContainer.append($message);
$overlayContainer.append($close);
$livePreviewPanel.append($overlayContainer);
}

/**
* responsible to hide the overlay
*/
function _hideOverlay() {
_clearConnectingOverlayTimer();
if ($overlayContainer) {
$overlayContainer.remove();
$overlayContainer = null;
}
}

/**
* This is a helper function that just checks that if connectingOverlayTimer exists, we clear it
*/
function _clearConnectingOverlayTimer() {
if (connectingOverlayTimer) {
clearTimeout(connectingOverlayTimer);
connectingOverlayTimer = null;
}
}

/**
* this function adds/remove the full-width class from the overlay container
* styled inside 'src/extensionsIntegrated/Phoenix-live-preview/live-preview.css'
*
* we need this because
* normally when live preview has a good width (more than 305px) then a 3px divider is shown at the left end
* so in that case we give the overlay a width of (100% - 3px),
* but when the live preview width is reduced
* then that divider line gets cut off, so in that case we make the width 100% for this overlay
*
* without this handling, a white gap appears on the left side, which is distracting
*/
function _setOverlayWidth() {
if(!$overlayContainer || !$livePreviewPanel.length) { return; }
if($livePreviewPanel.width() <= 305) {
$overlayContainer.addClass("full-width");
} else {
$overlayContainer.removeClass("full-width");
}
}

/** Initialize LiveDevelopment */
AppInit.appReady(function () {
params.parse();
Expand Down Expand Up @@ -443,19 +327,6 @@ define(function main(require, exports, module) {
exports.trigger(exports.EVENT_LIVE_PREVIEW_RELOAD, clientDetails);
});

MultiBrowserLiveDev.on(MultiBrowserLiveDev.EVENT_STATUS_CHANGE, function(event, status) {
if (status === MultiBrowserLiveDev.STATUS_CONNECTING) {
_handleOverlay(Strings.LIVE_DEV_STATUS_TIP_PROGRESS1, status);
} else if (status === MultiBrowserLiveDev.STATUS_SYNC_ERROR) {
_handleOverlay(Strings.LIVE_DEV_STATUS_TIP_SYNC_ERROR, status);
} else {
_hideOverlay();
}
});
// to understand why we need this, pls read the _setOverlayWidth function
new ResizeObserver(_setOverlayWidth).observe($("#main-plugin-panel")[0]);
EditorManager.on("activeEditorChange", _hideOverlay);

// allow live preview to handle escape key event
// Escape is mainly to hide boxes if they are visible
WorkspaceManager.addEscapeKeyEventHandler("livePreview", _handleLivePreviewEscapeKey);
Expand Down
15 changes: 10 additions & 5 deletions src/extensionsIntegrated/Phoenix-live-preview/live-preview.css
Original file line number Diff line number Diff line change
Expand Up @@ -171,17 +171,22 @@
}

.live-preview-overlay-message {
width: 100%;
color: #fff;
color: #ededed;
background-color: #666;
padding: 0.2em;
padding: 0.35em;
vertical-align: top;
text-align: center;
}

.live-preview-overlay-close {
position: absolute;
top: 4px;
right: 10px;
top: 7px;
right: 12px;
font-size: 12px;
cursor: pointer;
color: #ededed;
}

.live-preview-overlay-close:hover {
color: #fff;
}
Loading
Loading