Skip to content

Commit f91aff4

Browse files
committed
refactor: remote function LivePreviewView util
1 parent d237f25 commit f91aff4

File tree

1 file changed

+65
-63
lines changed

1 file changed

+65
-63
lines changed

src/LiveDevelopment/BrowserScripts/RemoteFunctions.js

Lines changed: 65 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,44 @@ function RemoteFunctions(config = {}) {
118118
return _moreOptionsHandlers[handlerName];
119119
}
120120

121-
const LivePreviewManager = {
121+
/**
122+
* check if an element is inspectable.
123+
* inspectable elements are those which doesn't have GLOBALS.DATA_BRACKETS_ID_ATTR ('data-brackets-id'),
124+
* this normally happens when content is DOM content is inserted by some scripting language
125+
*/
126+
function isElementInspectable(element, onlyHighlight = false) {
127+
if(config.mode !== 'edit' && !onlyHighlight) {
128+
return false;
129+
}
130+
131+
if(element && // element should exist
132+
element.tagName.toLowerCase() !== "body" && // shouldn't be the body tag
133+
element.tagName.toLowerCase() !== "html" && // shouldn't be the HTML tag
134+
!element.closest(`[${GLOBALS.PHCODE_INTERNAL_ATTR}]`) && // this attribute is used by phoenix internal elements
135+
!_isInsideHeadTag(element)) { // shouldn't be inside the head tag like meta tags and all
136+
return true;
137+
}
138+
return false;
139+
}
140+
141+
/**
142+
* This is a checker function for editable elements, it makes sure that the element satisfies all the required check
143+
* - When onlyHighlight is false → config.mode must be 'edit'
144+
* - When onlyHighlight is true → config.mode can be any mode (doesn't matter)
145+
* @param {DOMElement} element
146+
* @param {boolean} [onlyHighlight=false] - If true, bypasses the mode check
147+
* @returns {boolean} - True if the element is editable else false
148+
*/
149+
function isElementEditable(element, onlyHighlight = false) {
150+
// for an element to be editable it should satisfy all inspectable checks and should also have data-brackets-id
151+
return isElementInspectable(element, onlyHighlight) && element.hasAttribute(GLOBALS.DATA_BRACKETS_ID_ATTR);
152+
}
153+
154+
const LivePreviewView = {
122155
registerNodeMoreOptionsHandler: registerNodeMoreOptionsHandler,
123-
getNodeMoreOptionsHandler: getNodeMoreOptionsHandler
156+
getNodeMoreOptionsHandler: getNodeMoreOptionsHandler,
157+
isElementEditable: isElementEditable,
158+
isElementInspectable: isElementInspectable
124159
};
125160

126161
/**
@@ -190,39 +225,6 @@ function RemoteFunctions(config = {}) {
190225
return event.ctrlKey;
191226
}
192227

193-
/**
194-
* check if an element is inspectable.
195-
* inspectable elements are those which doesn't have GLOBALS.DATA_BRACKETS_ID_ATTR ('data-brackets-id'),
196-
* this normally happens when content is DOM content is inserted by some scripting language
197-
*/
198-
function isElementInspectable(element, onlyHighlight = false) {
199-
if(config.mode !== 'edit' && !onlyHighlight) {
200-
return false;
201-
}
202-
203-
if(element && // element should exist
204-
element.tagName.toLowerCase() !== "body" && // shouldn't be the body tag
205-
element.tagName.toLowerCase() !== "html" && // shouldn't be the HTML tag
206-
!element.closest(`[${GLOBALS.PHCODE_INTERNAL_ATTR}]`) && // this attribute is used by phoenix internal elements
207-
!_isInsideHeadTag(element)) { // shouldn't be inside the head tag like meta tags and all
208-
return true;
209-
}
210-
return false;
211-
}
212-
213-
/**
214-
* This is a checker function for editable elements, it makes sure that the element satisfies all the required check
215-
* - When onlyHighlight is false → config.mode must be 'edit'
216-
* - When onlyHighlight is true → config.mode can be any mode (doesn't matter)
217-
* @param {DOMElement} element
218-
* @param {boolean} [onlyHighlight=false] - If true, bypasses the mode check
219-
* @returns {boolean} - True if the element is editable else false
220-
*/
221-
function isElementEditable(element, onlyHighlight = false) {
222-
// for an element to be editable it should satisfy all inspectable checks and should also have data-brackets-id
223-
return isElementInspectable(element, onlyHighlight) && element.hasAttribute(GLOBALS.DATA_BRACKETS_ID_ATTR);
224-
}
225-
226228
// helper function to check if an element is inside the HEAD tag
227229
// we need this because we don't wanna trigger the element highlights on head tag and its children,
228230
// except for <style> tags which should be allowed
@@ -384,7 +386,7 @@ function RemoteFunctions(config = {}) {
384386
* @param {DOMElement} element - the HTML DOM element that was clicked.
385387
*/
386388
function _handleDeleteOptionClick(event, element) {
387-
if (isElementEditable(element)) {
389+
if (LivePreviewView.isElementEditable(element)) {
388390
const tagId = element.getAttribute(GLOBALS.DATA_BRACKETS_ID_ATTR);
389391

390392
window._Brackets_MessageBroker.send({
@@ -405,7 +407,7 @@ function RemoteFunctions(config = {}) {
405407
* @param {DOMElement} element - the HTML DOM element that was clicked.
406408
*/
407409
function _handleDuplicateOptionClick(event, element) {
408-
if (isElementEditable(element)) {
410+
if (LivePreviewView.isElementEditable(element)) {
409411
const tagId = element.getAttribute(GLOBALS.DATA_BRACKETS_ID_ATTR);
410412

411413
window._Brackets_MessageBroker.send({
@@ -427,7 +429,7 @@ function RemoteFunctions(config = {}) {
427429
* @param {DOMElement} element - the element we need to cut
428430
*/
429431
function _handleCutOptionClick(event, element) {
430-
if (isElementEditable(element)) {
432+
if (LivePreviewView.isElementEditable(element)) {
431433
const tagId = element.getAttribute(GLOBALS.DATA_BRACKETS_ID_ATTR);
432434

433435
window._Brackets_MessageBroker.send({
@@ -448,7 +450,7 @@ function RemoteFunctions(config = {}) {
448450
* @param {DOMElement} element
449451
*/
450452
function _handleCopyOptionClick(event, element) {
451-
if (isElementEditable(element)) {
453+
if (LivePreviewView.isElementEditable(element)) {
452454
const tagId = element.getAttribute(GLOBALS.DATA_BRACKETS_ID_ATTR);
453455

454456
window._Brackets_MessageBroker.send({
@@ -469,7 +471,7 @@ function RemoteFunctions(config = {}) {
469471
* @param {DOMElement} targetElement
470472
*/
471473
function _handlePasteOptionClick(event, targetElement) {
472-
if (isElementEditable(targetElement)) {
474+
if (LivePreviewView.isElementEditable(targetElement)) {
473475
const targetTagId = targetElement.getAttribute(GLOBALS.DATA_BRACKETS_ID_ATTR);
474476

475477
window._Brackets_MessageBroker.send({
@@ -491,12 +493,12 @@ function RemoteFunctions(config = {}) {
491493
* @param {DOMElement} element - the HTML DOM element that was clicked
492494
*/
493495
function _handleSelectParentOptionClick(event, element) {
494-
if (!isElementEditable(element)) {
496+
if (!LivePreviewView.isElementEditable(element)) {
495497
return;
496498
}
497499

498500
const parentElement = element.parentElement;
499-
if (isElementEditable(parentElement)) {
501+
if (LivePreviewView.isElementEditable(parentElement)) {
500502
// Check if parent element has .click() method (HTML elements)
501503
// SVG elements don't have .click() method, so we use _selectElement for them
502504
if (typeof parentElement.click === 'function') {
@@ -1278,7 +1280,7 @@ function RemoteFunctions(config = {}) {
12781280
let current = target.parentElement;
12791281

12801282
while (current) {
1281-
if (current.hasAttribute(GLOBALS.DATA_BRACKETS_ID_ATTR) && isElementEditable(current)) {
1283+
if (current.hasAttribute(GLOBALS.DATA_BRACKETS_ID_ATTR) && LivePreviewView.isElementEditable(current)) {
12821284
parents.push(current);
12831285
}
12841286

@@ -1462,7 +1464,7 @@ function RemoteFunctions(config = {}) {
14621464
let parent = currentElement.parentElement;
14631465

14641466
while (parent) {
1465-
if (parent.hasAttribute(GLOBALS.DATA_BRACKETS_ID_ATTR) && isElementEditable(parent)) {
1467+
if (parent.hasAttribute(GLOBALS.DATA_BRACKETS_ID_ATTR) && LivePreviewView.isElementEditable(parent)) {
14661468
const currentRect = currentElement.getBoundingClientRect();
14671469
const parentRect = parent.getBoundingClientRect();
14681470

@@ -1524,7 +1526,7 @@ function RemoteFunctions(config = {}) {
15241526
}
15251527

15261528
// Check if target is valid (not BODY, HTML or inside HEAD)
1527-
if (isElementEditable(target) && target !== SHARED_STATE._currentDraggedElement) {
1529+
if (LivePreviewView.isElementEditable(target) && target !== SHARED_STATE._currentDraggedElement) {
15281530
return target;
15291531
}
15301532
}
@@ -1580,7 +1582,7 @@ function RemoteFunctions(config = {}) {
15801582
target = target.parentElement;
15811583
}
15821584

1583-
if (!isElementEditable(target) || target === SHARED_STATE._currentDraggedElement) {
1585+
if (!LivePreviewView.isElementEditable(target) || target === SHARED_STATE._currentDraggedElement) {
15841586
if (_isAutoScrolling) { return; }
15851587
// if direct detection fails, we try to find a nearby valid target
15861588
target = _findNearestValidTarget(event.clientX, event.clientY);
@@ -1674,7 +1676,7 @@ function RemoteFunctions(config = {}) {
16741676
target = target.parentElement;
16751677
}
16761678

1677-
if (!isElementEditable(target) || target === SHARED_STATE._currentDraggedElement) {
1679+
if (!LivePreviewView.isElementEditable(target) || target === SHARED_STATE._currentDraggedElement) {
16781680
if (_isAutoScrolling) { return; }
16791681

16801682
// if direct detection fails, we try to find a nearby valid target
@@ -1689,7 +1691,7 @@ function RemoteFunctions(config = {}) {
16891691
}
16901692

16911693
// skip if no valid target found or if it's the dragged element
1692-
if (!isElementEditable(target) || target === SHARED_STATE._currentDraggedElement) {
1694+
if (!LivePreviewView.isElementEditable(target) || target === SHARED_STATE._currentDraggedElement) {
16931695
_clearDropMarkers();
16941696
_stopAutoScroll();
16951697
_dragEndChores(SHARED_STATE._currentDraggedElement);
@@ -1838,12 +1840,12 @@ function RemoteFunctions(config = {}) {
18381840
* @returns {boolean} - true if we should show the select parent option otherwise false
18391841
*/
18401842
function _shouldShowSelectParentOption(element) {
1841-
if(!isElementEditable(element)) {
1843+
if(!LivePreviewView.isElementEditable(element)) {
18421844
return false;
18431845
}
18441846

18451847
const parentElement = element.parentElement;
1846-
if(!isElementEditable(parentElement)) {
1848+
if(!LivePreviewView.isElementEditable(parentElement)) {
18471849
return false;
18481850
}
18491851
return true;
@@ -2939,7 +2941,7 @@ function RemoteFunctions(config = {}) {
29392941

29402942
_handleSend: function(event, prompt) {
29412943
const element = this.element;
2942-
if(!isElementEditable(element)) {
2944+
if(!LivePreviewView.isElementEditable(element)) {
29432945
return;
29442946
}
29452947
const tagId = element.getAttribute(GLOBALS.DATA_BRACKETS_ID_ATTR);
@@ -4618,7 +4620,7 @@ function RemoteFunctions(config = {}) {
46184620
function onMouseOver(event) {
46194621
if (_validEvent(event)) {
46204622
const element = event.target;
4621-
if(isElementInspectable(element) && element.nodeType === Node.ELEMENT_NODE ) {
4623+
if(LivePreviewView.isElementInspectable(element) && element.nodeType === Node.ELEMENT_NODE ) {
46224624
_localHighlight.add(element, true);
46234625
}
46244626
}
@@ -4707,7 +4709,7 @@ function RemoteFunctions(config = {}) {
47074709
}
47084710

47094711
const element = event.target;
4710-
if(!isElementInspectable(element) || element.nodeType !== Node.ELEMENT_NODE) {
4712+
if(!LivePreviewView.isElementInspectable(element) || element.nodeType !== Node.ELEMENT_NODE) {
47114713
return false;
47124714
}
47134715

@@ -4739,7 +4741,7 @@ function RemoteFunctions(config = {}) {
47394741
}
47404742

47414743
const element = event.target;
4742-
if(isElementEditable(element) && element.nodeType === Node.ELEMENT_NODE) {
4744+
if(LivePreviewView.isElementEditable(element) && element.nodeType === Node.ELEMENT_NODE) {
47434745
// this is to check the user's settings, if they want to show the elements highlights on hover or click
47444746
if (_hoverHighlight && shouldShowHighlightOnHover()) {
47454747
_hoverHighlight.clear();
@@ -4779,12 +4781,12 @@ function RemoteFunctions(config = {}) {
47794781
// this should also be there when users are in highlight mode
47804782
scrollElementToViewPort(element);
47814783

4782-
if(!isElementInspectable(element)) {
4784+
if(!LivePreviewView.isElementInspectable(element)) {
47834785
return false;
47844786
}
47854787

47864788
// if imageGallerySelected is true, show the image gallery directly (only for editable images)
4787-
if(isElementEditable(element) && element && element.tagName.toLowerCase() === 'img' && imageGallerySelected) {
4789+
if(LivePreviewView.isElementEditable(element) && element && element.tagName.toLowerCase() === 'img' && imageGallerySelected) {
47884790
if (!_imageRibbonGallery || _imageRibbonGallery.element !== element) {
47894791
dismissImageRibbonGallery(); // Dismiss only when creating new
47904792
_imageRibbonGallery = new ImageRibbonGallery(element);
@@ -4804,7 +4806,7 @@ function RemoteFunctions(config = {}) {
48044806
// make sure that the element is actually visible to the user
48054807
if (isElementVisible(element)) {
48064808
// Only show more options box for editable elements
4807-
if (isElementEditable(element)) {
4809+
if (LivePreviewView.isElementEditable(element)) {
48084810
_nodeMoreOptionsBox = new NodeMoreOptionsBox(element);
48094811
}
48104812
// Always show info box for inspectable elements
@@ -4878,7 +4880,7 @@ function RemoteFunctions(config = {}) {
48784880
* @param {Event} event - The click event
48794881
*/
48804882
function handleElementClick(element, event) {
4881-
if (!isElementInspectable(element)) {
4883+
if (!LivePreviewView.isElementInspectable(element)) {
48824884
dismissUIAndCleanupState();
48834885
return;
48844886
}
@@ -4940,7 +4942,7 @@ function RemoteFunctions(config = {}) {
49404942
handleElementClick(element, event);
49414943
}
49424944
} else if (eventType === "dblclick") {
4943-
if (isElementEditable(element) && _shouldShowEditTextOption(element)) {
4945+
if (LivePreviewView.isElementEditable(element) && _shouldShowEditTextOption(element)) {
49444946
startEditing(element);
49454947
}
49464948
}
@@ -5009,7 +5011,7 @@ function RemoteFunctions(config = {}) {
50095011
if (clear) {
50105012
_clickHighlight.clear();
50115013
}
5012-
if (isElementInspectable(element, true) && element.nodeType === Node.ELEMENT_NODE) {
5014+
if (LivePreviewView.isElementInspectable(element, true) && element.nodeType === Node.ELEMENT_NODE) {
50135015
_clickHighlight.add(element, true);
50145016
}
50155017
}
@@ -5029,7 +5031,7 @@ function RemoteFunctions(config = {}) {
50295031
// select the first valid highlighted element
50305032
var foundValidElement = false;
50315033
for (i = 0; i < nodes.length; i++) {
5032-
if(isElementInspectable(nodes[i], true) && nodes[i].tagName !== "BR") {
5034+
if(LivePreviewView.isElementInspectable(nodes[i], true) && nodes[i].tagName !== "BR") {
50335035
// only call _selectElement if it's a different element to avoid unnecessary box recreation
50345036
if (previouslyClickedElement !== nodes[i]) {
50355037
_selectElement(nodes[i]);
@@ -5819,7 +5821,7 @@ function RemoteFunctions(config = {}) {
58195821

58205822
// Function to handle direct editing of elements in the live preview
58215823
function startEditing(element) {
5822-
if (!isElementEditable(element)) {
5824+
if (!LivePreviewView.isElementEditable(element)) {
58235825
return;
58245826
}
58255827

@@ -5906,7 +5908,7 @@ function RemoteFunctions(config = {}) {
59065908
}
59075909

59085910
function finishEditingCleanup(element) {
5909-
if (!isElementEditable(element) || !element.hasAttribute("contenteditable")) {
5911+
if (!LivePreviewView.isElementEditable(element) || !element.hasAttribute("contenteditable")) {
59105912
return;
59115913
}
59125914

0 commit comments

Comments
 (0)