I've managed to get a solution:
Full interaction between Javascript inside the iframe and the VaadinUI (As the component to build has to be integrated in an existing VaadinUI) is possbile by:
1. Injecting Scripts, css and other needed Html Content into the loaded Webpage. The selection scripts of the solution were taken and extended from here
var elements = {
top: $('#selector-top'),
left: $('#selector-left'),
right: $('#selector-right'),
bottom: $('#selector-bottom')
};
function registerMouseMove() {
$(document).mousemove(function(event) {
if (event.target.id.indexOf('selector') !== -1 || event.target.tagName === 'BODY' || event.target.tagName === 'HTML') return;
var $target = $(event.target);
targetOffset = $target[0].getBoundingClientRect(),
targetHeight = targetOffset.height,
targetWidth = targetOffset.width;
//console.log(targetOffset);
elements.top.css({
left: (targetOffset.left - 4),
top: (targetOffset.top - 4),
width: (targetWidth + 5)
});
elements.bottom.css({
top: (targetOffset.top + targetHeight + 1),
left: (targetOffset.left - 3),
width: (targetWidth + 4)
});
elements.left.css({
left: (targetOffset.left - 5),
top: (targetOffset.top - 4),
height: (targetHeight + 8)
});
elements.right.css({
left: (targetOffset.left + targetWidth + 1),
top: (targetOffset.top - 4),
height: (targetHeight + 8)
});
});
};
function unregisterMouseMove() {
$(document).unbind();
elements.top.css({
left: 0,
top: 0,
width: 0
});
elements.bottom.css({
top: 0,
left: 0,
width: 0
});
elements.left.css({
left: 0,
top: 0,
height: 0
});
elements.right.css({
left: 0,
top: 0,
height: 0
});
};
function registerClickListener() {
$(document).click(function(event) {
if (event.target.id.indexOf('selector') !== -1 || event.target.tagName === 'BODY' || event.target.tagName === 'HTML')
return;
var target = event.target;
var xpath = Xpath.getElementXPath(target);
$.ajax({
type: "POST",
url: "/rest?text=" + xpath //,
});
console.log(xpath);
});
};
function unregisterClickListener() {
$(document).off("click");
}
function disableLinks() {
$('a').click(function(event) {
event.preventDefault();
});
}
function enableLinks() {
$('a').unbind('click');
}
function startSelecting() {
registerMouseMove();
registerClickListener();
disableLinks();
}
function stopSelecting() {
unregisterClickListener();
unregisterMouseMove();
enableLinks();
}
<!-- only for demonstration, delete! for use in programm call startSelecting by a Javascript call from the UI -->
window.onload = function(event) {
startSelecting();
};
#selector-top,
#selector-bottom {
background: blue;
height: 3px;
position: fixed;
transition: all 300ms ease;
}
#selector-left,
#selector-right {
background: blue;
width: 3px;
position: fixed;
transition: all 300ms ease;
}
<div id="selector">
<div id="selector-top"></div>
<div id="selector-left"></div>
<div id="selector-right"></div>
<div id="selector-bottom"></div>
</div>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js " /></script>
<script type="text/javascript" src="link/to/xpath.js"></script>
</head>
<body>
<span><b>Test</b></span>
<p>trallalalala</p>
</body>
</html>
2. Calling defined Javascripts inside the iframe using Vaadins Javascript calls (see here) and some Javascript path magic:
Page.getCurrent().getJavaScript().execute("window.frames[1].frameElement.contentWindow.startSelecting();");
3. Use Firebugs xpath.js script to get the XPath when clicking on an item (be aware of the license):
var xpath = Xpath.getElementXPath(event.target);
4. Use a ajax rest call to post data to your Vaadin Application:
$.ajax({
type: "POST",
url: "/rest?text="+xpath
});
5. Create a rest interface, thats using a Vaadin Broadcaster to broadcast the xpath value to the UI. For details on how to use the Broadcaster and Push for VaadinUI, see Eric G. post here
@RequestMapping("/rest")
public String sayHello(@RequestParam(value = "text", required = true) String text) {
Broadcaster.broadcast(text);
}
6. Finally: The VaadinUI receives the Broadcast and prints the xpath e.g. to a TextField and processes it further
The only downside of this is, that it can be only used for single user applications, as i not managed to differentiate between different instances of the same UI, i.e. one rest call will start a broadcast to all the instances of the UI and transport the same data to them.
I hope this helps future visitors. :)