I am a newbie in WATIR. The problem I am facing is -
The application I am testing has thumbnails (like Windows icons) placed on the page and I need to double click it. On doing that, an custom popup (ajax popup implemented in javascript) will open. The fire_event("ondblclick") is not working for me. I also tried 'click' twice but that too is not helping. Is there any other way of handling this? Your help is highly appreciated.
Added 6 July 2010:
I solved it but I have another query now.
Below was the HTML for which I was able to solve using "#ie.div(:class,'GridElementInlineIE').fire_event('ondblclick') "
<div class="gridViewItem" style='display: inline-table;' ondblclick='openAsset("634119577077187500", "", "LIBRARY_ASSETS_TAB", "1", "A111");'
id='GridComponent634119577077187500'>
<table style="display: inline-table;" class="gridViewItemTable" cellpadding="0" cellspacing="0"
onclick="highlightAsset(this, event)" projectid="" dmguid="634119577077187500"
id="_thumb_634119577077187500" objectclass="VIDEO">
<tr>
<td style="padding: 10px 10px 0px 7px">
<img class="assetListGridImage draggableThumbnail" id="thumb_634119577077187500"
title="A111" alt="A111"
src="/images/wait.gif" dmguid="634119577077187500" projectid=""
objectclass="VIDEO" _onclick="highlightAsset(this, event)" />
</td>
</tr>
<tr>
<td style="padding: 0px 0px 0px 7px">
A111
</td>
</tr>
<tr>
<td style="padding: 0px 0px 5px 7px; min-height: 33px; max-height: 33px; height: 33px;">
<img alt='Not starred' name='IMAGE634119577077187500' title='Star this asset' src='/Images/star_off.png' onclick='toggleStar(event, this, "634119577077187500")' class='starGrid' />
<img alt='video' title='video' src='/Images/asset_type/VIDEO.png'/>
<img src='/images/shared.png' title ='Shared' alt='Shared' />
</td>
</tr>
</table>
</div>
Now I need to double click on this item (code below). But even though the element is being identified (highlighted with a yellow), the double click is not working. I am trying "#ie.div(:class,'gridViewItem').fire_event('ondblclick')". I've also tried the while loops and click-twice options to no effect. I'm using Watir 1.6 with Ruby186-27_rc2.
div class="GridElementInline">
<table class="GridElementInline" style="border: solid 2px #1e606e;min-height:134px;height:134px;max-height: 134px" onclick="highlightAsset(this, event)"
projectid='' folderid="2383" id="_tblBinlist2383" title = "today">
<tr>
<td style="padding: 10px 10px 0px 7px;">
<table id='tblBinlist2383' folderid='2383' projectId='' _onclick='highlightAsset(this, event)' ondblclick='showBinDetails("2383", "")' class='binThumbnail GridElementInline' cellpadding='0' cellspacing='0'><tr><td><img class='fourGridViewImage' src='http://stream.....' /></td><td><img class='fourGridViewImage' src='http://stream.....' /></td></tr><tr><td><img class='fourGridViewImage' src='http://stream.....' /></td><td><img class='fourGridViewImage' src='http://stream.....' /></td></tr></table>
</td>
</tr>
<tr>
<td colspan="2" align="center" style="padding: 10px 10px 0px 7px; font-size: 9px;white-space: nowrap;">
<div align="left" title="today">
today
</div>
</td>
</tr>
</table>
</div>
There's one elegant solution I did for Watir 1.6.7 in Windows.
I went to ruby/lib/ruby/gems/1.8/gems/watir-1.6.7/lib/watir/element.rb (your path may change, but the main idea is to access the watir library and modify the element.rb file).
I added these lines:
def fire_event_no_wait(event)
assert_exists
assert_enabled
highlight(:set)
element = "#{self.class}.new(#{#page_container.attach_command}, :unique_number, # {self.unique_number})"
ruby_code = "require 'rubygems';" <<
"require '#{File.expand_path(File.dirname(__FILE__))}/core';" <<
"#{element}.fire_event(\"#{event}\")"
system(spawned_click_no_wait_command(ruby_code))
highlight(:clear)
end
this will create a method called fire_event_no_wait that behaves just like click_no_wait in watir.
Hope this helps anyone out.
EDIT You can get a better, working version of this code here now.
Here's a quick and slightly dirty workaround in case you get truly stuck with this. This ensures automatic relative hardware clicking to save the problems that the click event has (and traditionally, it has them in some corner cases).
Stick this in a file called, say, "mouseControl.rb" then link to it from your main file with require 'mouseControl'... or however you wish to go about it. It's been a while since I used it but I'm sure you can hack a double click out of it. I haven't included said hack because I happen to know this file works (or at least worked). You will need to require 'win32ole'. When you've got it set up you should be able to simply say things like #brower.button(:text, "boo").left_click to do a manual top-layer hardware click.
Should tide you over until you can get a better answer.
require 'watir'
module Watir
class Element
def top_edge
assert_exists
assert_enabled
ole_object.getBoundingClientRect.top.to_i
end
def top_edge_absolute
top_edge + page_container.document.parentWindow.screenTop.to_i
end
def left_edge
assert_exists
assert_enabled
ole_object.getBoundingClientRect.left.to_i
end
def left_edge_absolute
left_edge + page_container.document.parentWindow.screenLeft.to_i
end
def left_click
x = left_edge_absolute + 1
y = top_edge_absolute + 1
#puts "x: #{x}, y: #{y}"
WindowsInput.move_mouse(x, y)
WindowsInput.left_click
end
def right_click
x = left_edge_absolute
y = top_edge_absolute
#puts "x: #{x}, y: #{y}"
WindowsInput.move_mouse(x, y)
WindowsInput.right_click
end
end
end
module WindowsInput
# Windows API functions
SetCursorPos = Win32API.new('user32','SetCursorPos', 'II', 'I')
SendInput = Win32API.new('user32','SendInput', 'IPI', 'I')
# Windows API constants
INPUT_MOUSE = 0
MOUSEEVENTF_LEFTDOWN = 0x0002
MOUSEEVENTF_LEFTUP = 0x0004
MOUSEEVENTF_RIGHTDOWN = 0x0008
MOUSEEVENTF_RIGHTUP = 0x0010
module_function
def send_input(inputs)
n = inputs.size
ptr = inputs.collect {|i| i.to_s}.join # flatten arrays into single string
SendInput.call(n, ptr, inputs[0].size)
end
def create_mouse_input(mouse_flag)
mi = Array.new(7, 0)
mi[0] = INPUT_MOUSE
mi[4] = mouse_flag
mi.pack('LLLLLLL') # Pack array into a binary sequence usable to SendInput
end
def move_mouse(x, y)
SetCursorPos.call(x, y)
end
def left_click
leftdown = create_mouse_input(MOUSEEVENTF_LEFTDOWN)
leftup = create_mouse_input(MOUSEEVENTF_LEFTUP)
send_input( [leftdown, leftup] )
end
def right_click
rightdown = create_mouse_input(MOUSEEVENTF_RIGHTDOWN)
rightup = create_mouse_input(MOUSEEVENTF_RIGHTUP)
send_input( [rightdown, rightup] )
end
end
Related
I am trying to locate an element based on its text (I know, I know), and because there are two labels that contain some of the same words, I have to be able to locate it by some words but ensure it doesn't include other words. On top of that, it needs to be case insensitive.
Example: I am trying to locate and click the checkbox associated with the text Some Text, but not Some Text Too. The id and name, as well as the order (sometimes 'Some Text' is first, sometimes 'Some Text Too' is first) can vary from page to page depending on what else is shown, so I cannot rely on that to locate the correct checkbox.
<td style="padding-bottom: 2px"><input id="c_58" style="padding-left: 3px; background-color: rgb(255, 255, 255);" name="c_58" value="[dbo].[table].[Field]" type="checkbox"><label for="c_59" style="padding-left: 3px;">Some Text Too</label></td>
<td style="padding-bottom: 2px"><input id="c_59" style="padding-left: 3px; background-color: rgb(255, 255, 255);" name="c_59" value="[dbo].[table].[Field]" type="checkbox"><label for="c_59" style="padding-left: 3px;">Some Text</label></td>
What I have that works:
//*[*[text()[contains(translate(., 'SOME TEXT','some text'), 'some text')]]]
This finds the elements with 'Some Text', but also finds the elements with 'Some Text Too'. Since sometimes the page renders with the elements in different order, I need to be able to ensure I'm only finding 'Some Text' and not 'Some Text Too'
I have tried :
//*[*[text()[contains(translate(., 'SOME TEXT','some text'), 'some text') and not(contains(translate(., 'TOO', 'too'), 'too'))]]]
but that is not locating any element on the page.
Abdou you were correct - my scenario was more like:
label 1 : Some Text Here Too
label 2 : Some Texts Here
So the having the term "Some Text Here" couldn't find the second label because of the non-matching "Texts". I resolved this scenario by using:
//*[*[text()[contains(translate(., 'SOME','some'), 'some') and contains(translate(., 'TEXT','text'), 'text') and contains(translate(., 'HERE','here'), 'here') and not(contains(translate(., 'TOO','too'), 'too'))]]]
//*[*[text()[contains(translate(., 'SOME','some'), 'some') and contains(translate(., 'TEXT','text'), 'text') and contains(translate(., 'HERE','here'), 'here') and contains(translate(., 'TOO','too'), 'too')]]]
I have an issue with a classic ASP VBScript page which is starting to bug me. For the record I am not a web designer and I am working on somebody else code.
I have a strange issue where the first set of links that appear directly under a header cannot be clicked, but any after the first row can. I assume this is some kind of issue with overlapping elements on the page, but alas, the answer eludes me after 2 hours of trying to fix it.
Example below from the loop that creates the headers (the first loop). Any ideas as to why this is happening would be great.
Thanks
<div id="folderWrapper" style="width:100%; text-align:left; display:inline; float:left;">
<!-- Loop through the folders in the specific directories to find all that start with a "_" (where documents are stored) -->
<%
dim fs,fo,x
set fs=Server.CreateObject("Scripting.FileSystemObject")
set fo=fs.GetFolder(server.MapPath(department))
for each x in fo.SubFolders
%>
<%If Left(x.Name, 1) = "_" Then%>
<!-- Run the loop against only folders with the appendix of "_" as these are the folders with the files in.-->
<div id="folderDiv" style="width:100%; text-align:left; display:inline; float:left; padding-right:10px;">
<!-- Create headers for each folder-->
<h6><%Response.Write(Right(x.Name,len(x.Name)-1))%></h6>
<%
' Loop through files in folder
dim fs2,fo2,x2
set fs2=Server.CreateObject("Scripting.FileSystemObject")
set fo2=fs2.GetFolder(x)
for each x2 in fo2.files
' Set fileType variable depending upon the left 4 or 5 chars.
dim fileType
If (Right(x2.Name,4)=".doc") or (Right(x2.Name,4)=".pdf") Then
fileType = Right(x2.Name,4)
End If
If (Right(x2.Name,5)=".docx") Then
fileType = Right(x2.Name,5)
End If
%>
<!-- DIV to contain the files and display the correct icon for .doc/.docx and .pdf files-->
<div id="fileDiv" style="width:450px; float:left; display:inline; margin-left:10px; background-image:url(../images/<%if (right(x2.Name,4) = ".doc") or (right(x2.Name,4) = "docx") then %>Word_Icon.gif <%end if%> <%if(right(x2.Name,4) = ".pdf") then %>PDF_Icon.gif <% end if %> ); background-position:left; background-repeat:no-repeat; padding:10px 10px 10px 25px;" >
<%If fileType <> ".db" Then%>
<!-- If to deal with .doc and .pdf files (removes the .doc/.pdf extensions from the name when displayed on the page)-->
<%If (fileType=".doc") or (fileType=".pdf") Then%>
<%=left(x2.Name,len(x2.Name)-4)%>
<%End If%>
<!-- If to deal with .docx files (removes the .docx extensions from the name when displayed on the page)-->
<%If (fileType=".docx") Then %>
<%=left(x2.Name,len(x2.Name)-5)%>
<%End If%>
<%End If%>
</div>
<%next
set fo=nothing
set fs=nothing%>
<p> </p>
<p> </p>
</div>
<%End If%>
<%next
set fo=nothing
set fs=nothing%>
</div>
This was caused due to a tag overlapping the first div. This was originally intended to provide a buffer between the div before and this div but a this was removed and padding added instead.
I have a table layout like this:
<tbody>
<tr>
<td> 1 </td>
<td> <button> Click me </button>
</tr>
<tr>
<td> 2 </td>
<td> <button> Click me </button>
</tr>
....
</tbody>
I only know the value of the first td (1,2, etc). Is there anyway to click on the appropriate second td (the button) while only knowing the first td? For example, can I dynamically get 2 and know to click on the second "Click me" button instead of the first one?
yes there is way:
Basically, the buttons you want to click are siblings to the td elements you already know of.
Please try using locating an element via xpath sibling to locate those buttons:
//td[contains(text(),'1')]/following-sibling::* //this reads, first locate an element of td type whose text() attribute contains '1', then find its immediate sibling.
//td[contains(text(),'2')]/following-sibling::* //this reads, first locate an element of td type whose text() attribute contains '2', then find its immediate sibling.
You need an XPath:
twoClickMeButton = driver.find_element(:xpath,"//td[text()='2']/../td/button")
I've revised my original question because I'm new and can't reply to my own just yet... but here is my issues re-written, with more coding:
I'm using this as part of NetSuite, which is an accounting/ordering/CRM tool our company uses. We are allowed to customize our own estimates by using their form creation tool, which takes a combination of freemarker, html and xml to create our estimates.
I've designed a nice looking estimate and within this estimate I can call variables from the database. Basically shipping/billing info, items on the estimate and today I was able to add PAGE NUMBERS (Page 1 of 5 or Page 3 of 5) and place them at the bottom utilizing a FOOTER. However I wanted to also do this so that if my estimates ran multiple pages, I could print a header at the top so you'd see "Quantity, description, price" as I explained.
Now... I'm not exactly sure what the macros are for, this was how I wrote my page numbers and put them on the footer, which i'll show the code for in a bit.
I wanted to do something similar so that I could say "If we're not looking at page 1, print THIS header, but IF we're looking at Page 1, DONT print a header" so I figured i could do that page = page + 1 so it kept increasing. This idea WORKS in other parts of my estimate (for example, every item listed is on a seperate line on the estimate, and i actually print a line number, using that method, but that runs within its own routine later in the system via the LIST function)....
so any help getting this to work for my HEADER would be appreciated. I was hoping I could just do something simple such as "page = PAGENUMBER" but i can't utilize the built-in pagenumber variable for some reason, it doesnt quite work that way... here is what I have, in a simplified manor:
<!--?xml version="1.0"?-->
<pdf>
<head>
<style type="text/css">
STYLES HERE
</style>
<macrolist>
<macro id="footer">
<hr></hr>
<table border="0" width="100%">
<tr>
<#setting time_zone="America/New_York">
<td align="left">${.now}</td>
<td align="right">Page <pagenumber/> of <totalpages/></td>
</tr>
</table>
<hr></hr>
</macro>
</macrolist>
</head>
<body footer="footer" footer-height="12mm">
REGULAR HTML HERE FOR OUR COMPANY
<#if (record.item?size > 0)>
<table class="border" width="100%" cellpadding="2">
<#assign line = 0>
<#list record.item as item>
<#if item_index==0>
<tr>
<td width="5%" class="border4" valign="center"><b>Ln #</b></td>
<td width="5%" class="border4" valign="center"><b>Qty</b></td>
<td width="66%" class="border4" valign="center"><b>Description</b></td>
<td width="12%" class="border4" valign="center" align="right"><b>Unit Price</b></td>
<td width="12%" class="border5" valign="center" align="right"><b>Ext. Price</b></td>
</tr>
</table>
<table width="100%" cellpadding="7">
</#if>
<tr>
<#assign line = line + 1>
<td width="5%" valign="top">${line}</td>
<td width="5%" valign="top">${item.quantity}</td>
<td width="71%" valign="top">${item.description?html}<br /><i>Manuf. Part #: ${item.item.text}</i></td>
<td width="12%" valign="top" align="right">$${item.rate}</td>
<td width="12%" valign="top" align="right">$${item.amount}</td>
</#if>
</tr>
</#list>
</table>
</#if>
MORE HTML FOR OUR COMPANY HERE
</body>
</pdf>
So with all that said, any thoughts as to how I can utilize that "LN #, QTY, DESCRIPTION, UNIT PRICE, EXT. PRICE" as headers on pages 2 and on? (Page 1 has our letterhead at the top and some other html coding for our company)
As Yvan noted, this is not a freemaker question, but actually a bfo question. And as Shaun noted you can use the CSS id selector of #pagen to set header/footer for a given page. The problem with this is that all the existing documentation I've seen shows that if you use the #pagen CSS selector, then you have to define the CSS for every other page as well. So for example ...
/* If */
#page1 {
header: empty-header;
header-height: 0px;
}
/* Then */
#page2, #page3, #page4, ... #pagen {
header: default-header;
header-height: 10mm;
}
You basically have to guess what the maximum page size will be and add a CSS selector for each and every one of page. It might be safe enough to go up to 10 or something, because honestly whose going make an 11 page order, right?
Well if this doesn't sit right with you or you just don't like hard-coded limitations like this, then I believe I have an alternative. If one defines the default header on the <body> tag. Then define the #pagen CSS selector for just the page (or pages) you need (i.e. page 1 in your case,) but use the !important CSS property you'll get the desired results. For example this should do the trick...
<!--?xml version="1.0"?-->
<pdf>
<head>
<style type="text/css">
#page1 {
header: empty-header !important;
header-height: 0px !important;
}
</style>
<macrolist>
<macro id="empty-header">
<!-- Nothing to look at here -->
</macro>
<macro id="default-header">
<!-- Header HTML for all but first page -->
</macro>
</macrolist>
</head>
<body header="default-header" header-height="12mm">
<!-- Page body HTML -->
</body>
</pdf>
I don't know what macro and macrolist are (that's not FreeMarker), but I guess you simily shouldn't initialize count to 0 unless it's yet undefined. That is, instead of that two #assign-s you could write <#assign count = (count!0) + 1>. Of course it matters what the life-cycle of the FreeMarker Environment looks like, as the value of count will be lost if you start a new Environment (like call Template.process).
I'm using NetSuite too and ran into a somewhat similar problem. I don't think your problem is linked to Freemarker, but to Big Faceless Organization (BFO). Freemarker prepares the xml and BFO converts it into a PDF.
More information on BFO can be found here: http://bfo.com/products/report/. That's where you have the concept of header / footer / macros.
Read section "Pagination with tables - headers and footers" from page 35 of the User Guide which describes how to reprint a standard header or footer row in the table.
The table has to be top-level to work (i.e. not within another table.)
I don't yet know the answer to your question, but I can tell you that it may be found in the Big Faceless PDF Library user guide, not Freemarker...
http://bfo.com/products/report/docs/userguide.pdf
The answer relates to the application of special macros:
To display headers and footers on the page, the Report Generator introduces the concept of a “macro” - a block of XML which can be
repeated multiple times throughout the document.
There are three different types of macro attribute, which can be used either on the BODY or PBR elemnts to set a macro for every
page, or for a specific page by using a #pagen entry in a stylesheet.
header > to set the header of the page
footer > to set the footer of the page
background-macro > to set the background of the page
A macro is defined in the HEAD of the document inside a MACROLIST. Each macro must have an ID, which is how it’s referenced later in the document. Here’s an example which sets a standard footer on each page:
<pdf>
<head>
<macrolist>
<macro id="myfooter">
<p align="center">
Page <pagenumber/> of <totalpages/>
</p>
</macro>
</macrolist>
</head>
<body footer="myfooter" footer-height="20mm">
Document contents here
</body>
</pdf>
The “footer” attribute is the ID of the macro, and the “footer-height” attribute is the height required for the footer. If the document
contents require several pages, the footer will be placed on each one, unless there is a PBR element which changes the footer (or
removes it by setting footer="none"). The “header” attribute can be used the same way to set a header at the top of each page.
I know this answer is coming late for the question, but as I was trying to figure out the same thing I learned the answer from Russ's answer and the BFO documentation. Hopefully this will help anyone else out that is looking for the same information. Using the style attribute and the #pagen id you can set a header or footer to a specific page. nlfooter is the name of the footer macro. I am applying this footer to the first page only. Here is the code I used to apply a footer to the first page only.
<style type="text/css">
#page1 {
footer: nlfooter;
footer-height: 10%;
}
</style>
The comment from Russ with the quote from BFO's documentation helped me realize this. Here is the quote with emphasis added.
There are three different types of macro attribute, which can be used either on the BODY or PBR elemnts to set a macro for every page, or for a specific page by using a #pagen entry in a stylesheet.
I have made a website.It worked all fine during the whole development and testing phase of over 20 days during which I viewed the pages always in firefox and they were all fine.But today suddenly I encountered a problem with firefox. The table data are not centered and the borders are not rounded as they used to be earlier.But they are all fine in Google Chrome..You can view the screenshots :
Mozilla Firefox (It not used to be like this !)
Google Chrome
Please tell me how to fix it..I have cleared all the cache and session of firefox but still its the same
UPD
Ok so I am providing the codes as well:
The Php code (only snippet) of the table
$result = mysql_query("SELECT username,rating,contests,rank from users order by (rating) desc limit 10");
echo '<table id="problems">
<thead><tr>
<th colspan="3" align="center" ><font color="red" ><h2>Top Rated</h2></font></th>
</tr></thead>
<tr>
<th>#</th>
<th>Username</th>
<th >Rating </th>
</tr>';
while($row = mysql_fetch_array($result))
{
require_once("color_gen.php");
require_once("rankings.php");
ranker_rater();
$color=ColorGen($row['rating'],$row['contests']);
$uname=$row['username'];
$rank=$row['rank'];
echo "<tr>";
echo "<td>" . $rank. "</td>";
echo '<td><font color="'.$color.'">'.$uname.'</font></td>';
echo "<td>" . $row['rating'] . "</td>";
echo "</tr>";
}
echo "</table>";
And the corresponding CSS
#problems
{
text-align:centre;
border:solid;
border-width:2px;
border-color:#CCC;
width : 100%;
}
#problems th,td
{
padding: 4px;
font-weight: normal;
border:solid;
border-width:1px;
border-color:#CCC;
font-size: 15px;
color: #039;
//background: #b9c9fe;
text-align:center;
}
Know that different browsers have different default functions. This is the fundamental manner in which I attack this problem. Google chrome typically is more kind to web developers and is better at correcting errors. But, if you want something to be consistent throughout all browsers, ensure that the values are stated explicitly.
Problem 1 - Text not centered: I notice that in your CSS, your first line assigns text-align to "centre." The internet was founded by Americans, and all browsers will support the American spelling of "center." The problem is probably that Firefox does not support the British spelling of the word. I won't know until its tried, though.
Problem 2 - Corners not rounded: Since I am not a very skilled web developer, this is a problem I do not know how to solve. However, I've found a blog post by someone who does.