Skip to content

Commit d942ece

Browse files
committed
feat: live preview hover highlights improved
1 parent ce02c4b commit d942ece

File tree

2 files changed

+144
-4
lines changed

2 files changed

+144
-4
lines changed

src/LiveDevelopment/BrowserScripts/RemoteFunctions.js

Lines changed: 141 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,80 @@ function RemoteFunctions(config) {
212212

213213
};
214214

215+
// Node info box to display DOM node ID and classes on hover
216+
function NodeInfoBox(element) {
217+
this.element = element;
218+
this.remove = this.remove.bind(this);
219+
this.create();
220+
}
221+
222+
NodeInfoBox.prototype = {
223+
create: function() {
224+
// Remove existing info box if any
225+
this.remove();
226+
227+
// compute the position on screen
228+
var offset = _screenOffset(this.element),
229+
x = offset.left,
230+
y = offset.top - 30; // Position above the element
231+
232+
// create the container
233+
this.body = window.document.createElement("div");
234+
this.body.style.setProperty("z-index", 2147483647);
235+
this.body.style.setProperty("position", "fixed");
236+
this.body.style.setProperty("left", (offset.left) + "px");
237+
this.body.style.setProperty("top", (offset.top - 30 < 0 ? offset.top + this.element.offsetHeight + 5 : offset.top - 30) + "px");
238+
this.body.style.setProperty("font-size", "12px");
239+
this.body.style.setProperty("font-family", "Arial, sans-serif");
240+
241+
// Style the info box with a blue background
242+
this.body.style.setProperty("background", "#4285F4");
243+
this.body.style.setProperty("color", "white");
244+
this.body.style.setProperty("border-radius", "3px");
245+
this.body.style.setProperty("padding", "5px 8px");
246+
this.body.style.setProperty("box-shadow", "0 2px 5px rgba(0,0,0,0.2)");
247+
this.body.style.setProperty("max-width", "300px");
248+
this.body.style.setProperty("pointer-events", "none"); // Make it non-interactive
249+
250+
// Get element ID and classes
251+
var id = this.element.id;
252+
var classes = this.element.className ? this.element.className.split(/\s+/).filter(Boolean) : [];
253+
254+
// Create content for the info box
255+
var content = "";
256+
257+
// Add element tag name
258+
content += "<div style='font-weight: bold;'>" + this.element.tagName.toLowerCase() + "</div>";
259+
260+
// Add ID if present
261+
if (id) {
262+
content += "<div style='margin-top: 3px;'>#" + id + "</div>";
263+
}
264+
265+
// Add classes (limit to 3 with dropdown indicator)
266+
if (classes.length > 0) {
267+
content += "<div style='margin-top: 3px;'>";
268+
for (var i = 0; i < Math.min(classes.length, 3); i++) {
269+
content += "." + classes[i] + " ";
270+
}
271+
if (classes.length > 3) {
272+
content += "<span style='opacity: 0.8;'>+" + (classes.length - 3) + " more</span>";
273+
}
274+
content += "</div>";
275+
}
276+
277+
this.body.innerHTML = content;
278+
window.document.body.appendChild(this.body);
279+
},
280+
281+
remove: function() {
282+
if (this.body && this.body.parentNode) {
283+
window.document.body.removeChild(this.body);
284+
this.body = null;
285+
}
286+
}
287+
};
288+
215289
function Editor(element) {
216290
this.onBlur = this.onBlur.bind(this);
217291
this.onKeyPress = this.onKeyPress.bind(this);
@@ -565,14 +639,19 @@ function RemoteFunctions(config) {
565639
var _remoteHighlight;
566640
var _hoverHighlight;
567641
var _clickHighlight;
642+
var _nodeInfoBox;
568643
var _setup = false;
569644

570645

571646
/** Event Handlers ***********************************************************/
572647

573648
function onMouseOver(event) {
574649
if (_validEvent(event)) {
575-
_localHighlight.add(event.target, true);
650+
// Skip highlighting for HTML and BODY tags
651+
if (event.target && event.target.nodeType === Node.ELEMENT_NODE &&
652+
event.target.tagName !== "HTML" && event.target.tagName !== "BODY") {
653+
_localHighlight.add(event.target, true);
654+
}
576655
}
577656
}
578657

@@ -590,14 +669,45 @@ function RemoteFunctions(config) {
590669
function onElementHover(event) {
591670
if (_hoverHighlight) {
592671
_hoverHighlight.clear();
593-
_hoverHighlight.add(event.target, false);
672+
673+
// Skip highlighting for HTML and BODY tags
674+
if (event.target && event.target.nodeType === Node.ELEMENT_NODE &&
675+
event.target.tagName !== "HTML" && event.target.tagName !== "BODY") {
676+
// Store original background color to restore on hover out
677+
event.target._originalBackgroundColor = event.target.style.backgroundColor;
678+
event.target.style.backgroundColor = "rgba(0, 162, 255, 0.2)";
679+
680+
_hoverHighlight.add(event.target, false);
681+
682+
// Create info box for the hovered element
683+
if (_nodeInfoBox) {
684+
_nodeInfoBox.remove();
685+
}
686+
_nodeInfoBox = new NodeInfoBox(event.target);
687+
}
594688
}
595689
}
596690

597-
function onElementHoverOut() {
691+
function onElementHoverOut(event) {
598692
if (_hoverHighlight) {
599693
_hoverHighlight.clear();
600694
}
695+
696+
// Restore original background color
697+
if (event && event.target && event.target.nodeType === Node.ELEMENT_NODE) {
698+
if (event.target._originalBackgroundColor !== undefined) {
699+
event.target.style.backgroundColor = event.target._originalBackgroundColor;
700+
delete event.target._originalBackgroundColor;
701+
} else {
702+
event.target.style.backgroundColor = "";
703+
}
704+
}
705+
706+
// Remove info box when mouse leaves the element
707+
if (_nodeInfoBox) {
708+
_nodeInfoBox.remove();
709+
_nodeInfoBox = null;
710+
}
601711
}
602712

603713
function onClick(event) {
@@ -665,6 +775,10 @@ function RemoteFunctions(config) {
665775
if (_hoverHighlight) {
666776
_hoverHighlight.clear();
667777
}
778+
if (_nodeInfoBox) {
779+
_nodeInfoBox.remove();
780+
_nodeInfoBox = null;
781+
}
668782
}
669783

670784
// highlight a node
@@ -675,7 +789,11 @@ function RemoteFunctions(config) {
675789
if (clear) {
676790
_clickHighlight.clear();
677791
}
678-
_clickHighlight.add(node, true);
792+
// Skip highlighting for HTML and BODY tags
793+
if (node && node.nodeType === Node.ELEMENT_NODE &&
794+
node.tagName !== "HTML" && node.tagName !== "BODY") {
795+
_clickHighlight.add(node, true);
796+
}
679797
}
680798

681799
// highlight a rule
@@ -1015,7 +1133,26 @@ function RemoteFunctions(config) {
10151133
}
10161134

10171135
function updateConfig(newConfig) {
1136+
var oldConfig = config;
10181137
config = JSON.parse(newConfig);
1138+
1139+
if (config.highlight) {
1140+
// Add hover event listeners if highlight is enabled
1141+
window.document.removeEventListener("mouseover", onElementHover);
1142+
window.document.removeEventListener("mouseout", onElementHoverOut);
1143+
window.document.addEventListener("mouseover", onElementHover);
1144+
window.document.addEventListener("mouseout", onElementHoverOut);
1145+
} else {
1146+
// Remove hover event listeners if highlight is disabled
1147+
window.document.removeEventListener("mouseover", onElementHover);
1148+
window.document.removeEventListener("mouseout", onElementHoverOut);
1149+
1150+
// Remove info box if highlight is disabled
1151+
if (_nodeInfoBox) {
1152+
_nodeInfoBox.remove();
1153+
_nodeInfoBox = null;
1154+
}
1155+
}
10191156
return JSON.stringify(config);
10201157
}
10211158

src/LiveDevelopment/main.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,9 @@ define(function main(require, exports, module) {
298298
.on("change", function () {
299299
config.highlight = PreferencesManager.getViewState("livedevHighlight");
300300
_updateHighlightCheckmark();
301+
if (MultiBrowserLiveDev && MultiBrowserLiveDev.status >= MultiBrowserLiveDev.STATUS_ACTIVE) {
302+
MultiBrowserLiveDev.agents.remote.call("updateConfig",JSON.stringify(config));
303+
}
301304
});
302305

303306
config.highlight = PreferencesManager.getViewState("livedevHighlight");

0 commit comments

Comments
 (0)