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
48 changes: 27 additions & 21 deletions src/LiveDevelopment/BrowserScripts/RemoteFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
let _sourcelessClass = null;
const SOURCELESS_RECOVER_DELAY_MS = 60;
let _selectedFromEditor = false;
// the selected element the `phcode-no-lp-edit` opt-out is lifted for, see _isEditOptedOut
let _editOptOutOverride = null;
// the element selected by name (layers panel row), not by pointer
let _namedSelection = null;
// Expose the currently selected element globally for external access
window.__current_ph_lp_selected = null;

Expand Down Expand Up @@ -140,7 +140,7 @@
}

if(element && // element should exist
element.tagName.toLowerCase() !== "body" && // shouldn't be the body tag
(!isBodyElement(element) || _isNamedSelection(element)) && // body only when selected by name
element.tagName.toLowerCase() !== "html" && // shouldn't be the HTML tag
// this attribute is used by phoenix internal elements
!element.closest(`[${GLOBALS.PHCODE_INTERNAL_ATTR}]`) &&
Expand All @@ -151,19 +151,23 @@
return false;
}

// The body is never selected by pointer (blank clicks deselect, hover stays quiet),
// only by name from the layers panel or the caret, and then without the structural tools.
function isBodyElement(element) {

Check warning on line 156 in src/LiveDevelopment/BrowserScripts/RemoteFunctions.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Move function 'isBodyElement' to the outer scope.

See more on https://sonarcloud.io/project/issues?id=phcode-dev_phoenix&issues=AaCB3t0o0IGzlEckf3Fe&open=AaCB3t0o0IGzlEckf3Fe&pullRequest=3185
return !!(element && element.tagName && element.tagName.toLowerCase() === "body");

Check warning on line 157 in src/LiveDevelopment/BrowserScripts/RemoteFunctions.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer using an optional chain expression instead, as it's more concise and easier to read.

See more on https://sonarcloud.io/project/issues?id=phcode-dev_phoenix&issues=AaCB3t0o0IGzlEckf3Ff&open=AaCB3t0o0IGzlEckf3Ff&pullRequest=3185
}

// a named selection lifts the `phcode-no-lp-edit` opt-out and the body block, both pointer-only guards
function _isNamedSelection(element) {
return !!element && element === _namedSelection;
}

/**
* `phcode-no-lp-edit` cascades to descendants, `phcode-no-lp-edit-this` covers
* the one element.
*
* The opt-out exists so that a pointer landing on the page is read as the page's
* own business rather than as an edit, and a click still is: handleElementClick
* tests for it before anything else. But an element the editor named outright -
* a row picked in the layers panel - is being edited on purpose and there is
* nothing ambiguous to protect, so while such an element holds the selection
* every tool treats it like any other.
*/
function _isEditOptedOut(element) {
if (element === _editOptOutOverride) {
if (_isNamedSelection(element)) {
return false;
}
return !!(element.closest('.phcode-no-lp-edit') ||
Expand Down Expand Up @@ -246,6 +250,7 @@
getAllToolHandlers: getAllToolHandlers,
isElementEditable: isElementEditable,
isElementInspectable: isElementInspectable,
isBodyElement: isBodyElement,
isSourceless: isSourceless,
getElementRef: getElementRef,
getElementByRef: getElementByRef,
Expand Down Expand Up @@ -677,7 +682,8 @@
if (element === _lastHoverTarget) {
return;
}
if(!LivePreviewView.isElementInspectable(element) || element.nodeType !== Node.ELEMENT_NODE) {
if(isBodyElement(element) || !LivePreviewView.isElementInspectable(element) ||
element.nodeType !== Node.ELEMENT_NODE) {
return;
}
_lastHoverTarget = element;
Expand Down Expand Up @@ -737,11 +743,10 @@
* @param {boolean} [fromEditor] - If true, this is an editor-cursor-driven selection;
* only lightweight highlights (outline, margin/padding overlay) are shown, not interactive
* UI like control box, spacing handles, or measurements.
* @param {boolean} [ignoreEditOptOut] - Edit this element even though it opted
* out of live preview editing. For selections asked for by name from the
* editor side; holds only while the element stays selected.
* @param {boolean} [byName] - Selected by name (a layers panel row), so the edit
* opt-out and the body block don't apply while it stays selected.
*/
function selectElement(element, fromEditor, ignoreEditOptOut) {
function selectElement(element, fromEditor, byName) {
// When a cursor-based highlight re-selects the already-selected element,
// just refresh the highlight overlay without dismissing existing UI panels
// (control box, editor box, element-info). This prevents cursor activity
Expand All @@ -758,7 +763,7 @@

dismissUIAndCleanupState();
// set after the dismissal, which clears the previous selection's exemption
_editOptOutOverride = ignoreEditOptOut ? element : null;
_namedSelection = byName ? element : null;
// this should also be there when users are in highlight mode
scrollElementToViewPort(element);

Expand Down Expand Up @@ -939,7 +944,8 @@
if(element && (element.closest('.phcode-no-lp-edit') || element.classList.contains('phcode-no-lp-edit-this'))) {
return;
}
if (!LivePreviewView.isElementInspectable(element)) {
// a blank-space click lands on the body and deselects, even a body selected by name
if (isBodyElement(element) || !LivePreviewView.isElementInspectable(element)) {
dismissUIAndCleanupState();
return;
}
Expand Down Expand Up @@ -1093,7 +1099,7 @@
hideHighlight();

// Filter out the universal selector (*) from the rule - highlighting everything
// is not useful, similar to how we skip html/body in isElementInspectable.
// is not useful, similar to how we skip the html tag in isElementInspectable.
// The rule can be a comma-separated list of selectors (from multi-cursor),
// so we filter out any standalone * segments and keep valid ones.
rule = rule.split(",").map(s => s.trim()).filter(s => s !== "*").join(",");
Expand Down Expand Up @@ -1661,7 +1667,7 @@
window.__current_ph_lp_selected = null;
}
_unwatchSourcelessSelection();
_editOptOutOverride = null;
_namedSelection = null;

// Reset hover tracking so the same-element skip doesn't suppress
// re-highlighting after a full state cleanup (e.g. Escape, dismiss).
Expand Down Expand Up @@ -1761,7 +1767,7 @@

/**
* This function dismisses all UI elements and cleans up application state
* Called when user presses Esc key, clicks on HTML/Body tags, or other dismissal events
* Called when user presses Esc key, clicks on blank page space (the body), or other dismissal events
*/
function dismissUIAndCleanupState() {
getAllToolHandlers().forEach(handler => (handler.dismiss && handler.dismiss())); // to dismiss all UI boxes
Expand Down
17 changes: 16 additions & 1 deletion src/nls/root/strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -833,11 +833,16 @@ define({
"LIVE_PREVIEW_LAYERS_SCROLL_ON_HOVER": "Scroll to Element on Hover",
"LIVE_PREVIEW_LAYERS_MOVE_UP": "Move Up",
"LIVE_PREVIEW_LAYERS_MOVE_DOWN": "Move Down",
"LIVE_PREVIEW_LAYERS_COPIED_HINT": "Copied. Right-click a row to paste below it.",
"LIVE_PREVIEW_LAYERS_CUT_HINT": "Cut. Right-click a row to paste below it.",
"LIVE_PREVIEW_LAYERS_ADD_ATTRIBUTE": "Add Attribute",
"LIVE_PREVIEW_LAYERS_REMOVE_ATTRIBUTE": "Remove Attribute",
"LIVE_PREVIEW_LAYERS_PROPERTIES": "Properties",
"LIVE_PREVIEW_LAYERS_STYLES": "Styles",
"LIVE_PREVIEW_LAYERS_NO_SELECTION": "Select an element to see its details",
"LIVE_PREVIEW_LAYERS_MAXIMIZE_SECTION": "Expand Section",
"LIVE_PREVIEW_LAYERS_RESTORE_SECTIONS": "Restore Sections",
"LIVE_PREVIEW_LAYERS_NO_SELECTION_PROPERTIES": "Select an element to see its properties",
"LIVE_PREVIEW_LAYERS_NO_SELECTION_STYLES": "Select an element to see its styles",
"LIVE_PREVIEW_LAYERS_NOT_IN_SOURCE": "This element is not in the source file",
"LIVE_PREVIEW_LAYERS_NO_STYLES": "No styles applied",
"LIVE_PREVIEW_LAYERS_OPEN_SOURCE": "Open in editor",
Expand All @@ -849,6 +854,16 @@ define({
"LIVE_PREVIEW_LAYERS_SHOW_SCRIPT_NODES": "Show Script-Generated Elements",
"LIVE_PREVIEW_LAYERS_SCRIPT_GENERATED": "Generated by script, not in the source file",
"LIVE_PREVIEW_LAYERS_TAG_TOOLTIP": "Show Tag Name Tooltip",
"LIVE_PREVIEW_LAYERS_INSERT_ELEMENT": "Insert Element",
"LIVE_PREVIEW_LAYERS_INSERT_INTO_PAGE": "Add to the page",
"LIVE_PREVIEW_LAYERS_INSERT_LOADING": "Loading elements…",
"LIVE_PREVIEW_LAYERS_INSERT_UNAVAILABLE": "The live preview did not answer. Try again in a moment.",
"LIVE_PREVIEW_LAYERS_EMPTY_PAGE": "This page has no elements yet.",
"LIVE_PREVIEW_LAYERS_ADD_ELEMENT": "Add an element",
"LIVE_PREVIEW_LAYERS_EMPTY_PAGE_PROPERTIES": "The page is empty. Add an element to see its properties.",
"LIVE_PREVIEW_LAYERS_EMPTY_PAGE_STYLES": "The page is empty. Add an element to see its styles.",
"LIVE_PREVIEW_LAYERS_SHOW_SELECTED": "Show the selected element",
"LIVE_PREVIEW_LAYERS_SCRUB_HINT": "Drag to adjust, double-click to edit",

"LIVE_DEV_DETACHED_REPLACED_WITH_DEVTOOLS": "Live Preview was canceled because the browser's developer tools were opened",
"LIVE_DEV_DETACHED_TARGET_CLOSED": "Live Preview was canceled because the page was closed in the browser",
Expand Down
Loading
Loading