I'm currently building a Vaadin Webapp for getting the path of certain HTML-Elements from a website. Therefore, i want to
load a webpage inside an IFrame / BrowserFrame of a Vaadin Page
let the user visually click on an highlighted HTML-Element (in a way like http://selectorgadget.com/)
generate the Path (XPath seems to be the best choice) and
display it inside a formular of the Vaadin Page (on the same site, as to check the selections)
My questions:
Is the transfer of the path data from the website inside the iFrame to the Vaadin App actually possible?
Is the selection of html elements possible with techniques provided by the Vaadin App (so that i do not need any Javascript inside the IFrame)?
Is there some technology other than iFrames to better accomplish my goal?
Thanks in advance!
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. :)
Related
This is site:
https://play.alienworlds.io/
I need to click on the login button.
In HTML I can't find it...
<body>
<div class="webgl-content">
<div id="unityContainer" style="width: 1528px; height: 355px; padding: 0px; margin: 0px; border: 0px; position: relative; background: url("Build/fff2a664dc06d7254246c6bb8d5d0e21.jpg") center center / cover;">
<canvas id="#canvas" style="width: 100%; height: 100%; cursor: default;" width="1528" height="355"></canvas>
<div class="logo " style="display: none;"></div>
<div class="progress Dark" style="display: none;">
<div class="empty" style="width: 0%;"></div>
<div class="full" style="width: 100%;"></div>
</div>
</div>
</div>
<script src="Build/061f463856577255fb5eefaf73e67127.js" type="text/javascript"></script>
<script src="bundle.js" type="text/javascript"></script>
<script src="hashes.js" type="text/javascript"></script>
<script src="message_handler.js" type="text/javascript"></script>
<script type="text/javascript">
// Initial screen setup
unityContainer.style.height = window.innerHeight + "px";
unityInstance = UnityLoader.instantiate(
"unityContainer",
"Build/bd2a2f07495f744fece3ee93c4a56908.json",
{ onProgress: UnityProgress }
);
function Resize() {
document.getElementById('unityContainer').style.width =
window.innerWidth + 'px';
document.getElementById('unityContainer').style.height =
window.innerHeight + 'px';
if (UnityLoader.SystemInfo.mobile) {
if (navigator.userAgent.indexOf('Android') != -1)
{
if (screen.width > screen.height) {
unityInstance.SendMessage("Canvas", "SetScreenModePanel", "false");
}
else
{
unityInstance.SendMessage("Canvas", "SetScreenModePanel", "true");
}
}
else
{
switch (window.orientation) {
case -90:
case 90:
unityInstance.SendMessage('Canvas', 'SetScreenModePanel', 'false');
break;
default:
unityInstance.SendMessage('Canvas', 'SetScreenModePanel', 'true');
break;
}
}
}
}
/*function Fullscreen() {
unityInstance.SetFullscreen(1);
if (navigator.userAgent.indexOf('Android') != -1)
window.screen.orientation.lock('landscape');
}*/
window.addEventListener('orientationchange', Resize);
// Initial execution if needed
//Resize();
</script>
<script src="blob:https://play.alienworlds.io/9ffeac95-ddb2-480b-a75f-a20043229a5b" id="0941210686ad38c201cd5aecd353ebd4"></script>
</body>
The question is tricky.
I've added the answer in Python. It uncovers the concept. If you can't, I will translate the answer to Java. The approach to such tasks is really what you need.
I could click login button with ActionChains class.
Please not that this is not very stable case for few reasons:
1 It depends on screen resolution, so you should set the resolution after your browser is opened
2 You will need to add waits (replace time.sleep() with Selenium's waits)
3 You cannot move your mouse while test is executing because it will break your actions
4 And the biggest problem on my opinion is that after you click the button, you will be dealing with Captcha.
This is my code which I used while debugging. You should set screen resolution because most probably your coordinates will be different.
import time
from selenium import webdriver
from selenium.webdriver import ActionChains
driver = webdriver.Chrome(executable_path='/snap/bin/chromium.chromedriver')
url = "https://play.alienworlds.io/"
driver.get(url)
driver.set_window_size(1522, 754) # setting window size to be sure what resolution you work with
time.sleep(20)
driver.implicitly_wait(25)
canvas = driver.find_element_by_css_selector("canvas[id='#canvas']")
print(driver.get_window_size()) # print to make sure window size is correct
drawing = ActionChains(driver)
print("moving by offset")
drawing.move_by_offset(450, 511)
print("clicking")
drawing.click()
print("clicked")
drawing.perform()
print("performed")
time.sleep(5) # just to check that a new window is opened
driver.close()
driver.quit()
I could improve it, but it is not 5 minutes task.
Good luck!
p.s. move_by_offset moves the cursor from the upper left corner of your screen.
Update:
I've added driver.set_window_size(1522, 754) This is the canvas resolution I get when I inspect canvas element.
I print print(driver.get_window_size()) to make sure the screen resolution is as expected.
I've tried few tools to measure browser window size and found out that My Ruler extension by Leann Pagac works the best for canvas. All other extensions, even they are more commonly used could not measure coordinates on the canvas correctly.
Also, check this post to get more details on how to work with canvas How to perform Mouse Wheel scrolling over HTML5 Canvas in Selenium?
I have couple of jqgrids on a page..Now I want to reload both the jqgrids after i update a record in any of them.
Here is my body..
<div style="position: relative; top: 40px; width:50%">
<table id="list"><tr><td></td></tr></table>
<div id="pager"></div>
</div>
<div style="position: relative; top: -250px; left:50%;">
<table id="list1"><tr><td></td></tr></table>
<div id="pager1"></div>
</div>
and Here is the script for after submit function of first jqgrid...
afterSubmit: function (response, postdata)
{
if (response.responseText === "OK")
{
alert("Update is succefully");
alert(this);
$(this).jqGrid("setGridParam", {datatype: 'json'});
return [true, "", ""];
alert("#list1");
$("#list1").jqGrid("setGridParam", {datatype: 'json'});
return [true, "", ""];
// $(this).trigger('reloadGrid');
}
else {
alert("Update failed");
return [true, "", ""];
}
}
Now using this code my first jqgrid does get reloaded after updating data and shows updated data in that jqgrid, However second jqgrid which has id #list1 doesn't get reloaded/refreshed.How do I Achieve this?
It's unclear which changes exactly you mean. If you use free jqGrid fork, then the recommended way to reload the grid from the server, if it has loadonce: true option, would be to use .trigger("reloadGrid", {fromServer: true}) or $("#list").trigger("reloadGrid", [{fromServer: true, current: true, page: 1}]); (see the answer or this one). Thus you can do the following:
$(".ui-jqgrid-btable").trigger("reloadGrid", {fromServer: true});
If you need to trigger reloading of the grid inside of some callback like afterSubmit then I recommend you to wrap the above code in the setTimeout to allow to finish processing of the afterSubmit before reloading of the grid:
afterSubmit: function () {
setTimeout(function () {
$(".ui-jqgrid-btable").trigger("reloadGrid", {fromServer: true});
}, 50);
return [true, "", ""];
}
Is there any way I can get the properties of an element on which I place the cursor on? I will be using a JavaFX browser to load the websites. So I cannot use firebug or any plugins. Is there any possibility to achieve this? Please help.
Its just like Inspect Element in Firebug.
In JavaScript, when this "choose an element" mode is activated, you can attach a mouseover handler to the document. This will receive repeated calls as the mouse moves over elements. You can tell which element the mouse is over via the target property on the event object, e.g.:
document.addEventListener("mouseover", function(e) {
// Use e.target to know which element it is
}, false);
Then simply look at the element. You might also hook mouseout to know when you leave an element.
There are limits to this. For instance, you can't get a list of event handlers attached to it through a normal DOM API.
Here's a simple example demonstrating the handler:
var lastElement = null;
var display = document.getElementById("display");
document.addEventListener("mouseover", function(e) {
if (e.target != lastElement) {
lastElement = e.target;
show("tag", lastElement.tagName);
show("id", lastElement.id);
show("name", lastElement.name);
show("class", lastElement.className);
show("style-color", lastElement.style.color);
show("computed-color", getComputedStyle(lastElement).color);
}
}, false);
document.addEventListener("mouseout", function(e) {
var n, list;
if (e.target == lastElement) {
list = display.querySelector("span");
for (n = 0; n < list.length; ++n) {
list[n].innerHTML = "";
}
lastElement = null;
}
}, false);
function show(type, text) {
display.querySelector("." + type).innerHTML = text;
}
.foo {
color: green;
}
<p id="main-paragraph">
This is a test, with
<strong class="foo">various elements</strong>
that you can
<em style="color: blue">mouse over</em>.
<input type="text" name="the-input">
</p>
<div id="display">
<div>tag: <span class="tag"></span></div>
<div>id: <span class="id"></span></div>
<div>name: <span class="name"></span></div>
<div>class: <span class="class"></span></div>
<div>style.color: <span class="style-color"></span></div>
<div>computedStyle.color: <span class="computed-color"></span></div>
</div>
I want to pass a variable from HTML to Java. For this, I wrote the following code:
<!doctype html>
<html>
<title>How to create a typewriter or typing effect with jQuery</title>
<div id="example1">fsdfsdfojsdlk sdfj lskdhfk sdf </div>
<style>
body{
background: transparent;
color: #ec5a62;
}
#container{
font-size: 7em;
}
</style>
</head>
<body>
<div id="container"></div>
<!--
We use Google's CDN to serve the jQuery js libs.
To speed up the page load we put these scripts at the bottom of the page
-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>
<script>
//define text
var text = ("document.getElementById("example1")");
//text is split up to letters
$.each(text.split(''), function(i, letter){
//we add 100*i ms delay to each letter
setTimeout(function(){
//we add the letter to the container
$('#container').html($('#container').html() + letter);
}, 30*i);
});
</script>
</body>
</html>
But it is not working. How can I achieve this?
Please do help me.
I'm using var text =("document.getElementById("example1")");
But its not working.
to get value use var x=document.getElementById("example1").value;
your code should be like this:
var text=document.getElementById("example1").value;
//text is split up to letters
$.each(text.split(''), function(i, letter){
//we add 100*i ms delay to each letter
setTimeout(function(){
//we add the letter to the container
$('#container').html($('#container').html() + letter);
}, 30*i);
});
I'm writing online shopping application using Struts 2.
In front-end I'm using jsp, twitter bootstrap, jquery, moustache.js template, twbs pagination plugin and some javascript.
I have Product entity and I want to display the list of products to the user in jsp page.
The way I'm doing it is async loading page with fix number(20) of products in json format and then obtaining them using mustache template.
All my code works except the time when user the first time sees this jsp page - first 20 products are not displaying. So when I'm moving from page to page it loads info, but as twbs plugin works through firing events it means that event is not triggered after jsp page loaded the first time.
So my question is whats the truly good way to fix this ?
Should I fire an event once or use $(document).ready() or $(document).onload() ?
I'm not an expert in javascript, so please be patient
<html>
<%# include file="/WEB-INF/jspf/head.jspf"%>
<body>
<%# include file="/WEB-INF/jspf/menu.jspf"%>
<div class="container">
<ul class="sync-pagination pagination"></ul>
<div id="products" style="width: 50%"></div>
<ul class="sync-pagination pagination"></ul>
</div>
<script type="text/javascript"
src="webjars/mustachejs/0.8.2/mustache.js"></script>
<script id="products-template" type="text/mustache-template">
<ul class="list-group">
{{#.}}
<li class="list-group-item">
<label for="{{name}}">Name: /label> {{name}}
</br>
<label for="{{price}}">Price: </label> {{price}}
</br>
Full description...
</li>
{{/.}}
</ul>
</script>
<script type="text/javascript"
src="script/jquery.twbsPagination.min.js"></script>
<script type="text/javascript">
var records = "${requestScope.records}";
var recordsPerPage = 20;
var pages = Math.ceil(records / recordsPerPage);
$('.sync-pagination').twbsPagination({
totalPages : pages,
visiblePages : 7,
onPageClick : function(event, page) {
$('#products').html(changePage(page));
}
});
function changePage(page) {
pnumber = page || 1;
$.ajax({
type : 'GET',
dataType : 'json',
url : 'product/upload_products?page=' + pnumber,
success : function(products) {
var template = $('#products-template').html();
var info = Mustache.render(template, products);
$('#products').html(info);
}
})
}
</script>
</body>
</html>
You need to call changePage(); on the initial load. You might also want to call this when the page finishes loading everything by using $(document).ready();
<script type="text/javascript">
var records = "${requestScope.records}";
var recordsPerPage = 20;
var pages = Math.ceil(records / recordsPerPage);
$('.sync-pagination').twbsPagination({
totalPages : pages,
visiblePages : 7,
onPageClick : function(event, page) {
$('#products').html(changePage(page));
}
});
function changePage(page) {
pnumber = page || 1;
$.ajax({
type : 'GET',
dataType : 'json',
url : 'product/upload_products?page=' + pnumber,
success : function(products) {
var template = $('#products-template').html();
var info = Mustache.render(template, products);
$('#products').html(info);
}
})
}
//Add this in here
changePage();
</script>