|
30 | 30 | */ |
31 | 31 | function RemoteFunctions(config) { |
32 | 32 |
|
| 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; |
33 | 36 |
|
34 | 37 | var experimental; |
35 | 38 | if (!config) { |
@@ -212,6 +215,98 @@ function RemoteFunctions(config) { |
212 | 215 |
|
213 | 216 | }; |
214 | 217 |
|
| 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 | + |
215 | 310 | // Node info box to display DOM node ID and classes on hover |
216 | 311 | function NodeInfoBox(element) { |
217 | 312 | this.element = element; |
@@ -640,6 +735,7 @@ function RemoteFunctions(config) { |
640 | 735 | var _hoverHighlight; |
641 | 736 | var _clickHighlight; |
642 | 737 | var _nodeInfoBox; |
| 738 | + var _nodeMoreOptionsBox; |
643 | 739 | var _setup = false; |
644 | 740 |
|
645 | 741 |
|
@@ -710,15 +806,20 @@ function RemoteFunctions(config) { |
710 | 806 | } |
711 | 807 | } |
712 | 808 |
|
| 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 | + */ |
713 | 814 | 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; |
721 | 821 | } |
| 822 | + _nodeMoreOptionsBox = new NodeMoreOptionsBox(event.target); |
722 | 823 | } |
723 | 824 | } |
724 | 825 |
|
@@ -1247,6 +1348,7 @@ function RemoteFunctions(config) { |
1247 | 1348 | // Add event listeners for hover |
1248 | 1349 | window.document.addEventListener("mouseover", onElementHover); |
1249 | 1350 | window.document.addEventListener("mouseout", onElementHoverOut); |
| 1351 | + window.document.addEventListener("click", onClick); |
1250 | 1352 |
|
1251 | 1353 | if (experimental) { |
1252 | 1354 | window.document.addEventListener("keydown", onKeyDown); |
|
0 commit comments