html - Highlight Deepest Child DOM Element with Div Overlay when Moused Over in Pure Javascript -
the short version:
i want mimic google chrome's inspect element tool in pure javascript.
the long version:
i working on extension google chrome. want implement similar inspect element tool in pure javascript (no jquery or other libraries/frameworks/dependencies). if uses adblock, want mimic "block ad on page" functionality allows user select element on page.
while extension active, user should able to:
- mouse on element
- if 'p' element
'code' element nested inside
being moused over, entire 'p' element should have 'div' overlay on - if mouse moves on nested
'code' element
should re-size 'div' overlay cover only deeper nested'code' element
- when clicked, underlying element should stored , 'div' overlay hidden
why use 'div' overlay instead of adding class element adds border/outline/background color?
the overlay prevents user directly interacting element. if there href/onclick attribute not want activate when clicked.
can write stores inline 'onclick' attributes, sets them null/return false; , restores original 'onclick' code?
tried that:
onclicks = document.queryselectorall('[onclick]'); saved = []; // disable onclicks function disableonclicks() { (var = 0; < onclicks.length; i++) { saved[i] = onclicks[i].clonenode(); onclicks[i].onclick = "return false;"; }; console.log("onclicks disabled"); } // enable onclicks function enableonclicks() { (var = 0; < onclicks.length; i++) { onclicks[i].onclick = saved[i].onclick; }; console.log("onclicks enabled"); } // if injecting script, make sure elements have loaded window.onload = function(){ disableonclicks(); console.log("onclicks disabled"); enableonclicks(); console.log("onclicks enabled"); }
unfortunately, doesn't handle invisible event listeners may on given page.
my current code formatted paste console:
// css highlight element var overlaycss = document.createelement("style"); overlaycss.type = "text/css"; overlaycss.innerhtml = "body .highlight-element{z-index:2147483647!important}.highlight-element{background-color:rgba(130,180,230,.4);outline:#0f4d9a solid 1px;box-sizing:border-box;position:absolute;display:none}"; document.body.appendchild(overlaycss); // append style tag body // create div overlay highlight elements & prevent onclick events var overlay = document.createelement("div"); overlay.classname = "highlight-element"; document.body.appendchild(overlay); // append div overlay body // check if overlay appended if (overlay === document.getelementsbyclassname('highlight-element')[0]) { console.log("overlay exists"); }; // positions div overlay based on targetrect aka element.getboundingclientrect() function moveoverlay (targetrect) { var overlay = document.getelementsbyclassname('highlight-element')[0]; // correct page scroll overlay.style.top = (targetrect.top + window.scrolly) + "px"; overlay.style.left = targetrect.left + "px"; overlay.style.height = targetrect.height + "px"; overlay.style.width = targetrect.width + "px"; overlay.style.display = "block"; } // set start time lastfire var lastfire = date.now(); function getinnermosthovered(e) { // difference between , last event var difference = date.now() - lastfire; // console.log(difference); // delay handling mousemove milliseconds // making 0 may induce epileptic shock... if (difference > 100) { // prevent endless highlight loop if (e.target.getattribute('class') == "highlight-element") { e.target.style.display = "none"; } // element under mouse var n = document.queryselector(":hover"); var nn; // deepest child element has :hover while (n) { nn = n; n = nn.queryselector(":hover"); } console.log("nn: " + nn); // dimensions pass div overlay var targetrect = nn.getboundingclientrect(); // console.log(targetrect.top); // display overlay div @ element position under mouse moveoverlay(targetrect); // event fired, overwrite last fire time lastfire = date.now(); } } // onmousemove deepest child element under mouse document.addeventlistener('mousemove', getinnermosthovered, false);
feel free test out on page (refresh page cancel), have overlay sort-of working alternating displaying/hiding overlay 'div' on 'mousemove' event. ideally want run smooth chrome's inspect element , give me element data. , ideas appreciated, must stress want in pure javascript.
edit: solved document.elementfrompoint(x,y)
!
after few days of research, able find simple solution problem. code work pasted in chrome's console, press esc cancel.
var rootnode = document.documentelement; var currentnode = currentnode || {}; var lastnode = lastnode || {}; var nodeclone = nodeclone || {}; var prevonclick = prevonclick || {}; function nodehandler (e) { var x = e.clientx; var y = e.clienty; // console.log(x+", "+y); currentnode = document.elementfrompoint(x, y); if (currentnode === rootnode || currentnode === document.body){ // if current node html or body, nothing } else { if (currentnode === lastnode) { // if still on same node, nothing // console.log('same node'); } else { // console.log('different node'); // if lastnode has classlist, check onclick attribute , remove highlight-element class if (lastnode.classlist) { // if lastnode had onclick attribute, replace untouched value nodeclone if (lastnode.getattribute("onclick") != null) { prevonclick = nodeclone.getattribute("onclick"); lastnode.setattribute("onclick", prevonclick); } lastnode.classlist.remove('highlight-element'); } // save currentnode , preserve inline event (onclick) attributes nodeclone = currentnode.clonenode(); // if currentnode has onclick attribute, disable if (currentnode.getattribute("onclick")) { currentnode.setattribute("onclick", "return false;"); }; // add highlight class currentnode currentnode.classlist.add('highlight-element'); } // store node lastnode = currentnode; } } function clickhandler (e) { e.preventdefault(); e.stoppropagation(); e.stopimmediatepropagation(); console.log("clicked node:\n"); console.log(nodeclone); } function cancelnodeselect (e) { if (e.keycode == 27) { // if lastnode has classlist, check onclick attribute , remove highlight-element class if (lastnode.classlist) { if (lastnode.getattribute("onclick") != null) { prevonclick = nodeclone.getattribute("onclick"); lastnode.setattribute("onclick", prevonclick); } lastnode.classlist.remove('highlight-element'); } // remove event listeners document.removeeventlistener('click', clickhandler, false); document.removeeventlistener('mousemove', nodehandler, false); document.removeeventlistener('keyup', cancelnodeselect, false); console.log("escape pressed"); }; } document.addeventlistener('click', clickhandler, false); document.addeventlistener('mousemove', nodehandler, false); document.addeventlistener('keyup', cancelnodeselect, false);
edit 2: forgot add css using
.highlight-element { background-color: rgba(130, 180, 230, 0.4); outline: solid 1px #0f4d9a; box-sizing: border-box; }
Comments
Post a Comment