Skip to content

Commit 740acea

Browse files
committed
feat: create the DOM manipulation option box when an element is clicked in the live preview
1 parent adb1623 commit 740acea

File tree

1 file changed

+109
-7
lines changed

1 file changed

+109
-7
lines changed

src/LiveDevelopment/BrowserScripts/RemoteFunctions.js

Lines changed: 109 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
*/
3131
function RemoteFunctions(config) {
3232

33+
// this is responsible to make the advanced DOM features active or inactive
34+
// TODO: give this var a better name
35+
let isFlagActive = true;
3336

3437
var experimental;
3538
if (!config) {
@@ -212,6 +215,98 @@ function RemoteFunctions(config) {
212215

213216
};
214217

218+
/**
219+
* This is for the advanced DOM options that appears when a DOM element is clicked
220+
* advanced options like: 'select parent', 'duplicate', 'delete'
221+
*/
222+
function NodeMoreOptionsBox(element) {
223+
this.element = element;
224+
this.remove = this.remove.bind(this);
225+
this.create();
226+
}
227+
228+
NodeMoreOptionsBox.prototype = {
229+
create: function() {
230+
// Remove existing more options box if any
231+
this.remove();
232+
233+
// compute the position on screen (this gives us the left and the top offset)
234+
var offset = _screenOffset(this.element);
235+
// we need to fetch the height & width of the element to place the box at the correct position
236+
var elementSize = this.element.getBoundingClientRect();
237+
238+
// for styling the svg's
239+
if (!document.getElementById("node-more-options-style")) {
240+
const style = document.createElement("style");
241+
style.id = "node-more-options-style";
242+
style.textContent = `
243+
.node-options span > svg {
244+
width: 16px;
245+
height: 16px;
246+
display: block;
247+
}
248+
`;
249+
document.head.appendChild(style);
250+
}
251+
252+
// create the container
253+
this.body = window.document.createElement("div");
254+
this.body.style.setProperty("z-index", 2147483647);
255+
this.body.style.setProperty("position", "fixed");
256+
this.body.style.setProperty("left", (offset.left + (elementSize.width - 40)) + "px");
257+
this.body.style.setProperty("top", (offset.top - 30 < 0 ? offset.top + this.element.offsetHeight + 5 : offset.top - 30) + "px");
258+
this.body.style.setProperty("font-size", "12px");
259+
this.body.style.setProperty("font-family", "Arial, sans-serif");
260+
261+
// style the box with a blue background. this will appear on the right side of the clicked DOM element
262+
this.body.style.setProperty("background", "#4285F4");
263+
this.body.style.setProperty("color", "white");
264+
this.body.style.setProperty("border-radius", "3px");
265+
this.body.style.setProperty("padding", "5px 8px");
266+
this.body.style.setProperty("box-shadow", "0 2px 5px rgba(0,0,0,0.2)");
267+
this.body.style.setProperty("max-width", "82px");
268+
this.body.style.setProperty("width", "82px");
269+
this.body.style.setProperty("pointer-events", "none");
270+
271+
const ICONS = {
272+
arrowUp: `<svg viewBox="0 0 24 24" fill="currentColor">
273+
<path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.59 5.58L20 12l-8-8-8 8z"/>
274+
</svg>`,
275+
276+
copy: `<svg viewBox="0 0 24 24" fill="currentColor">
277+
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/>
278+
</svg>`,
279+
280+
trash: `<svg viewBox="0 0 24 24" fill="currentColor">
281+
<path d="M6 7V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v2h3v2h-2l-1.5 12.5a2 2 0 0 1-2 1.5H8.5a2 2 0 0 1-2-1.5L5 9H3V7h3zm2 0h8V5H8v2z"/>
282+
</svg>`
283+
};
284+
285+
let content = `<div class="node-options" style="display: flex; gap: 8px; align-items: center;">
286+
<span style="cursor: pointer; display: flex; align-items: center;" data-action="select-parent" title="Select Parent">
287+
${ICONS.arrowUp}
288+
</span>
289+
<span style="cursor: pointer; display: flex; align-items: center;" data-action="duplicate" title="Duplicate">
290+
${ICONS.copy}
291+
</span>
292+
<span style="cursor: pointer; display: flex; align-items: center;" data-action="delete" title="Delete">
293+
${ICONS.trash}
294+
</span>
295+
</div>`;
296+
297+
298+
this.body.innerHTML = content;
299+
window.document.body.appendChild(this.body);
300+
},
301+
302+
remove: function() {
303+
if (this.body && this.body.parentNode) {
304+
window.document.body.removeChild(this.body);
305+
this.body = null;
306+
}
307+
}
308+
};
309+
215310
// Node info box to display DOM node ID and classes on hover
216311
function NodeInfoBox(element) {
217312
this.element = element;
@@ -640,6 +735,7 @@ function RemoteFunctions(config) {
640735
var _hoverHighlight;
641736
var _clickHighlight;
642737
var _nodeInfoBox;
738+
var _nodeMoreOptionsBox;
643739
var _setup = false;
644740

645741

@@ -710,15 +806,20 @@ function RemoteFunctions(config) {
710806
}
711807
}
712808

809+
/**
810+
* This function handles the click event on the live preview DOM element
811+
* it is to show the advanced DOM manipulation options in the live preview
812+
* @param {Event} event
813+
*/
713814
function onClick(event) {
714-
if (_validEvent(event)) {
715-
event.preventDefault();
716-
event.stopPropagation();
717-
if (event.altKey) {
718-
_toggleEditor(event.target);
719-
} else {
720-
_toggleMenu(event.target);
815+
// make sure that the feature is enabled and also the clicked element has the attribute 'data-brackets-id'
816+
if(isFlagActive && event.target.hasAttribute('data-brackets-id')) {
817+
console.log("event:", event);
818+
if(_nodeMoreOptionsBox) {
819+
_nodeMoreOptionsBox.remove();
820+
_nodeMoreOptionsBox = null;
721821
}
822+
_nodeMoreOptionsBox = new NodeMoreOptionsBox(event.target);
722823
}
723824
}
724825

@@ -1247,6 +1348,7 @@ function RemoteFunctions(config) {
12471348
// Add event listeners for hover
12481349
window.document.addEventListener("mouseover", onElementHover);
12491350
window.document.addEventListener("mouseout", onElementHoverOut);
1351+
window.document.addEventListener("click", onClick);
12501352

12511353
if (experimental) {
12521354
window.document.addEventListener("keydown", onKeyDown);

0 commit comments

Comments
 (0)