On my page, I have an element (Drag Source) that is outside the frames and an element (Drop Target) that is inside a frame and in Shadow DOM.
The iframe has the attribute droppable=true, and the body tag inside the iframe has the drop event listener.
A simplified illustration is below:
<html>
<body>
<iframe droppable="true">
<html>
<body ondragover="window.NW.td.dragOverHandler(event.target,event);return false;" ondragleave="window.NW.td.dragLeaveHandler(event.target,event);return false;">
<macroponent>
#shadow-root
<nw-head>
<h1>Drop target</h1>
</nw-head>
</macroponent>
</body>
</html>
</iframe>
<span draggable="true">Drag source</span>
</body>
</html>
I am following the JavaScript solution from JavaScript workaround for drag and drop in Selenium WebDriver post to achieve drag and drop as solutions with Actions class haven't worked on this page.
It seems the drag and drop on the Drop Target is happening with the JS solution provided. I could check this by adding a eventListener in the JS code in the simulateDragDrop function like below and the alert gets displayed.
$.simulateDragDrop = function(elem, options) {
this.options = options;
options.dropTarget.addEventListener('drop',()=>{alert('dropped')});
this.simulateEvent(elem, options);
};
However, the drop event/ondragleave doesn't seem to get invoked as the expected result after drag and drop is not seen on the page. I'm not sure if this is due to the target element being in the Shadow DOM. What is it that may need to be done to get this to work?
composedPath() method returns the full path of nodes from the window object to the element on which the event was dispatched. This path includes the shadow boundary if the event was dispatched within a shadow root.
$.simulateDragDrop = function(elem, options) {
this.options = options;
var path = options.dropTarget.composedPath();
path[0].addEventListener('drop',()=>{alert('dropped')});
this.simulateEvent(elem, options);
};
Related
I need to get clickevent's screenX/screenY and clientX/clientY (Coordinates) of an HTML DOM element by programatically simulating click event on it, simplified code shown below.
Problem: When the element is manually clicked - the Coordinates are fine and present (as can be inspected in the console), HOWEVER when programatically clicked, the Coordinates are all 0.
Q1: Why the coordinates are 0 (we have a well positioned element) ?
Q2: What can be adjusted, so as to get the coordinates ?
Note: The ultimate goal is to devise a C# Selenium IJavaScriptExecutor compatible JavaScript code, so as to capture (any-set-of) current Coordinates of an HTML element with known id attribute (the captured Coordinates to be further used as input coordinates for creation and simulation of a mousewheel event, needed for zooming).
<!DOCTYPE html>
<html>
<body>
<h1> Hello </h1>
<h1 id="num1">TEST</h1>
<script>
var myVar = document.getElementById("num1");
myVar.onclick = function(event){ myFunc(event); }; // manually working fine
myVar.click(); // not yielding Coordinates
function myFunc(e){
console.log(e);
}
</script>
</body>
</html>
Q1: If your mouse was outside browser\page window,when you simulate click, it probably will be 0\0.
Q2: Something like this should solve your problem
I dispose of the following code :
<!DOCTYPE html>
<body>
<a id="toto" contenteditable="true">Button</a>
</body>
<script>
var elt= document.getElementById('toto');
elt.focus();
</script>
</html>
When the page is loaded, the cursor is already in place and you just have to type what you want. The trouble is that it doesn't work with IE11.
Since this works with other tags like <div>, I assume I just have to make <a> focusable for IE. Any ideas how ?
There are two issues here. First, IE automatically focuses on the body element after the page has loaded. So if your code is exactly as in the question, it will set focus on the a element but this will be overridden a few nanoseconds later, after the load event is triggered. A simple way to avoid this is to make sure the focus is set only after load. Example:
<a id="toto" contenteditable="true">Button</a>
<script>
window.onload = function() {
var elt= document.getElementById('toto');
elt.focus();
}
</script>
But IE also seems to have an issue with setting focus on an a element without an href attribute. Whatever the cause might be, you can circumvent this a) by adding href="javascript:;", but this is awkward and causes link formatting to be applied, or b) by changing the a element to e.g. a span element;
I am loading local HTML file in IFrame using HTML/Javascript in windows store development(Windows 8). I am trying get Swipe event from Iframe.
I tried with this sample & this. I fallowed the Mouse wheel scenario which contains one div element.
For Iframe it doesn't work.
My code:
<body>
<iframe id="iframe_Id" src="split.html" style="height:768px; width:1366px;" onload="Load();"></iframe>
</body>
function Load() {
var elt = document.getElementById("iframe_Id");
elt.style.backgroundColor = "#f3f3f3";
var gobj = new MSGesture();
// Defining gesture object for Pen, mouse and touch
gobj.target = elt;
elt.gesture = gobj;
elt.gesture.pointerType = null;
// Creating event listeners for gesture elements
elt.addEventListener("MSPointerDown", onPointerDown, false);
elt.addEventListener("MSGestureTap", onTap, false);
elt.addEventListener("MSGestureHold", onHold, false);
elt.addEventListener("MSGestureChange", onGestureChange, false);
// Mouse Wheel does not generate onPointerUp
elt.addEventListener("MSGestureEnd", onGestureEnd, false);
}
function onPointerDown(e) {
var content = document.getElementById("iframe_Id");
}
I created functions for all the events. But when swipe in my IFrame the event not raised.
I structured here. I need to work with Swipe. Please help me to out from this.
If split.html is a local file, you should listen for the events from within the iframe. You can then use parent.postMessage() to communicate up to the host/parent HTML page.
Alternatively, you can investigate the new WebView control available to HTML/JavaScript apps in Windows 8.1.
You should put your <iframe> inside a <div> block, like this :
<body>
<div id="watch">
<iframe id="iframe_Id" src="split.html" style="height:768px;
width:1366px;" onload="Load();">
</iframe>
</div>
</body>
And then you look the swipe in the div#watch instead of the iframe, because the touch event will be in the DOM and not in the iframe.
<embed id="bottom" src="img/model/skirt.svg" onclick="control.colorClothes(this)" title="bottom" type="image/svg+xml" width="325" height="500"> </embed>
I want to cause an event to fire on a mouse click.
The above works if I use onload and onmouseover, but not onclick or onmouseup/down.
Any thoughts?
** Edit **
My thanks to the posters. The code I was looking for is
onload="this.getSVGDocument().onclick = function(event){alert(333);};"
It overcomes three separate problems.
The delay in loading the svg file causing issues with code trying to execute on an svg file that didn't exist yet.
That the onclick event has to be attached to the svg element. I'm not sure why, Tanzeels post showed this & my experiments confirmed it.
The way I was trying to write the onclick="alert(333)" wasn't working. The above does. Again I'm not sure why, but at this point I'm just happy to go with the flow.
You will need to assign the click handler onto the SVG. Do something on the following lines:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function getClick(event) {
var clickedElement = event.target;
alert(clickedElement);
//console.log(clickedElement);
return;
}
function addClick() {
var embedObj = document.getElementById("bottom");
embedObj.getSVGDocument().onclick = function (event) {
return getClick(event);
};
return;
}
</script>
</head>
<body onload="addClick();">
<embed id="bottom" src="img/model/skirt.svg" title="bottom" type="image/svg+xml"
width="628" height="709"></embed>
</body>
</html>
The event.target will return the SVG node that was clicked.
Note that this approach will not work for cross-domain SVG resources as the browser will throw a permission denied error when assigning the onclick event handler.
it might be worth trying to wrap the embed tag in a div and put the onclick handler on that. I'm not sure if click events bubble out of svgs into the normal DOM but if they do then you should be ok. Like this:
<div onclick="control.colorClothes(this)"><embed id="bottom" src="img/model/skirt.svg" onclick="control.colorClothes(this)" title="bottom" type="image/svg+xml" width="325" height="500"></embed></div>
I need to edit (using javascript) an SVG document embedded in an html page.
When the SVG is loaded, I can access the dom of the SVG and its elements. But I am not able to know if the SVG dom is ready or not, so I cant' perform default actions on the SVG when the html page is loaded.
To access the SVG dom, I use this code:
var svg = document.getElementById("chart").getSVGDocument();
where "chart" is the id of the embed element.
If I try to access the SVG when the html document is ready, in this way:
jQuery(document).ready( function() {
var svg = document.getElementById("chart").getSVGDocument();
...
svg is always null. I just need to know when it is not null, so I can start manipulate it.
Do you know if there is a way to do it?
On your embedding element (e.g 'embed', 'object', 'iframe') in the main document add an onload attribute which calls your function, or add the event listener in script, e.g embeddingElm.addEventListener('load', callbackFunction, false). Another option might be to listen for DOMContentLoaded, depends on what you want it for.
You can also add a load listener on the main document. jQuery(document).ready doesn't mean that all resources are loaded, just that the document itself has a DOM that is ready for action. However note that if you listen for load on the entire document your callback function won't be called until all resources in that document are loaded, css, javascript etc.
If you use inline svg, then jQuery(document).ready will work just fine however.
On a further note you might want to consider using embeddingElm.contentDocument (if available) instead of embeddingElm.getSVGDocument().
You could use an onload event for the check.
Suppose some.svg is embedded in object tag :
<body>
<object id="svgholder" data="some.svg" type="image/svg+xml"></object>
</body>
Jquery
var svgholder = $('body').find("object#svgholder");
svgholder.load("image/svg+xml", function() {
alert("some svg loaded");
});
javascript
var svgholder = document.getElementById("svgholder");
svgholder.onload = function() {
alert("some svg loaded");
}
Assuming your SVG is in an <embed> tag:
<embed id="embedded-image" src="image.svg" type="image/svg+xml" />
The SVG image is essentially in a sub-document that will have a separate load event to that of the main document. However, you can listen for this event and handle it:
var embed = document.getElementById("embedded-image");
embed.addEventListener('load', function()
{
var svg = embed.getSVGDocument();
// Operate upon the SVG DOM here
});
This is better than polling as any modification you make to the SVG will happen before it is first painted, reducing flicker and CPU effort spent painting.
The load event of the embedding element (e.g. object) would be my preference but, if that isn't a viable solution for some reason, the only generic and reliable test I've found for SVG DOM ready is the getCurrentTime method of the SVG root element:
var element = document.getElementById( 'elementId' );
var svgDoc = element.contentDocument;
var svgRoot = svgDoc ? svgDoc.rootElement : null;
if ( svgRoot
&& svgRoot.getCurrentTime
&& ( svgRoot.getCurrentTime() > 0 ))
{
/* SVG DOM ready */
}
The W3C SVG recommendation states that getCurrentTime on an SVGSVGElement:
Returns the current time in seconds relative to the start time for the current SVG document fragment. If getCurrentTime is called before the document timeline has begun (for example, by script running in a ‘script’ element before the document's SVGLoad event is dispatched), then 0 is returned.
Using jQuery you can bind to the window load event Erik mentions with:
$(window).load(function(){
var svg = document.getElementById("chart").getSVGDocument();
});
For future reference: an Angular(8)/Typescript solution looks like this:
#ViewChild('startimage', {static:false})
private startimage: ElementRef;
...
this.startimage.nativeElement.addEventListener('load', () => {
alert('loaded');
});
You can get to the svg by const svg = this.startimage.nativeElement.getSVGDocument();
You can assign an onload event handler to an element within your SVG document and have it call a javascript function in the html page. onload maps to SVGLoad.
http://www.w3.org/TR/SVG11/interact.html#LoadEvent
The event is triggered at the point at which the user agent has fully parsed the element and its descendants and is ready to act appropriately upon that element
You could try polling every so often.
function checkReady() {
var svg = document.getElementById("chart").getSVGDocument();
if (svg == null) {
setTimeout("checkReady()", 300);
} else {
...
}
}