Scroll by a variable double or float in Selenium (Java) - javascript

I'm new to Selenium and revisiting programming in general after a long hiatus, so apologies if this isn't a good question. I have a webpage with a bunch of tiles (typically 4 per row, a whole bunch of rows) whose height and width vary based on the size of the window. After every row I want to scroll up by the height of one tile. Here's what I have (where eachtile is a list containing all the tiles):
double ImageHeight = eachtile.getSize().getHeight();
double f = 1.04*ImageHeight;
((JavascriptExecutor)driver).executeScript("window.scrollBy(0,-f);");
I've tried all variations of quotes and minus signs in the (0,-f) expression and no matter what I get an error saying that f is undefined. Does anyone know what to do here?

Try this
((JavascriptExecutor)driver).executeScript("window.scrollBy(0,arguments[0]);",-f);
Thanks!!

Or try another way, scroll to the next item in the list each time:
for (WebElement tile : tileList) {
js.executeScript("arguments[0].scrollIntoView();", tile);
}

Related

Move to center a selected object with scrollableWidth and scrollToHorizontalOffset

I am having a number (10) of objects which are clickable, but struggling with moving a selected one to the middle of the scroll view. You can see on the image below that number four is selected but not in the middle.
I tried to use:
myScrollView.scrollToHorizontalOffset(myScrollView.scrollableWidth / 2, true)
But it always bring the whole scroll view into the middle. Can anyone help with making it working? Thank you in advance.
Since You didn't put the Angular tag, I am assuming you are using the Typescript flavor of Nativescript.
In order to do this, you'd have to find a way keep track of your base (starting point) and your target (the one that the user just clicked) so that you can get there x offsets and animate the scroll from one to another.
Here's an example in your code behind:
export function() {
const base = page.getViewById('label1') as Label;
const target = page.getViewById('label2') as Label;
myScrollView.scrollToHorizontalOffset(target.getLocationRelativeTo(base).x, true);
}
Now, the code above will just do a minimum scroll to get to your target element (and you can use a different element other than the example label). But if you want to make it center, you can add an additional offset depending on how wide your scroll container is.
eg.
myScrollView.scrollToHorizontalOffset(target.getLocationRelativeTo(base).x + (myScrollView.width / 2), true);
Note that this is my hypothesis from something similar I've done before (just not needing to be center). So might need to play with the additional offset.
EDIT: (This is how to make it work specifically according to the OPs need)
myScrollView.scrollToHorizontalOffset(target.getLocationRelativeTo(base).x - (myScrollView.scrollableWidth / 2)), true);

Creating a Page Break in HTML

I am creating a resume using html and some elements have multiple lines. For example, an education can have the institute, the date attended, and the degree received on separate lines. However, the institute, the date, and the degree are all part of one record.
I am trying to create a page break when I print using html. I only want the page break to be inserted if the number of lines in the next element is greater than the number of lines remaining on the 8.5 x 11 page. Using the example earlier, I want all of the lines in the education record all on one page. The data is being passed in, so the page breaks can vary from resume to resume.
I have found code to create the page break: #media print {footer {page-break-after: always;}}.
I have also found code that can get the line height of a div:
var element = document.getElementById('content');
document.defaultView.getComputedStyle(element,null).getPropertyValue("lineHeight");
I need to count the number of lines remaining on the 8x11 page and compare that height to the height of the next element. Instead of using page breaks, another option would be to just add enough empty lines to move the element down enough for it to be all on one page, but I still need to be able to count the remaining lines. I would appreciate any suggestions. Thanks.
EDIT: Here is my code so far:
var totalHeight = 1056;
var divHeight = document.getElementById('element').offsetHeight;
totalHeight = totalHeight - divHeight;
if(totalHeight < 0)
{
document.write("<style>");
document.write("#media print {#element {page-break-after: always;}}");
document.write("</style>");
}
However, when I print out the total height it only returns a number slightly over 200. Instead, the number should exceed 1056. Does the offsetHeight method only return the size of the text itself and not the spacing around it or is there another problem that could be causing the drastic difference? Thanks.
I think the trickiest part here is dealing with whatever margin the browser will put on the page when it goes to print. Not sure if you can control that. But if you can, try using in as your sizing unit instead of something like px or em. Then, if you calculate that you're going to go over 11in with what you've got, add your page break.
Here's a pseudo-code algorithm:
var totalHeight = page margin
foreach div:
totalHeight += calculated height in inches
if totalHeight > 11in:
insert page break
rinse and repeat for further pages

Adding an absolute positioned element causes line break

So I have a "cursor" object created like so:
var cursor=document.createElement('span');
cursor.id="currentCursor";
cursor.innerHTML="|";
cursor.style.fontWeight="bold";
cursor.style.position = 'absolute';
cursor.style.marginLeft="-1px";
Then I add it to the page where someone clicks with this:
var selection = window.getSelection();
var currentRange = selection.getRangeAt(0);
currentRange.insertNode(cursor);
The problem I'm running into is in certain places (mainly end of lines) if the cursor object is added it creates a line break before the object. Using insertNode to move it to another area removes the line break. Also if I set the display to "none", wait for a few seconds and then set it back to "inline" the line break is removed.
This seems like maybe a browser bug in adding absolute elements, but I was wondering if someone had a workaround. I've tried setting the width to 0px but it has no effect.
Update
So if I change the cursor to
cursor.style.position = 'static';
It doesn't have random line breaks. However this causes space to be created around the element. Any way to not allow elements to create space around them?
Update 2
Added a fiddle to show the problem:
http://jsfiddle.net/Mctittles/pSg2D/1/
Original code is a bit large but I slimmed it down to highlight this problem.
If you click at the end of the smiley face and then type it causes line 33 to trigger creating a new text node. After typing a couple letters you'll see the cursor object is forced to the next line. Clicking somewhere else to move it makes the lines merge again.
If you un-comment lines 38 and 40 you'll see what I was talking about with making it initially display:none and changing it later. This time it doesn't cause a line break.
I took out some cross-browser code for fiddler, so this might only work in Chrome
However [position:static] causes space to be created around the element.
No, it doesn’t cause it – there is no actual space created “around it”, it’s just the display width of a character plus spacing in the used font, and that gives the span element itself a width that is more than the | character itself. But when you position the element absolutely, you don’t notice that, because it is taken out of the flow, so it doesn’t push the following characters to the right.
My workaround proposal: Don’t put | into the span as innerHTML, but leave it empty – and then implement the line by giving the element a border-left:1px solid. Remove position:absolute, so that it defaults to static.
Then you might probably not like the height your cursor is getting with that – but that can be fixed as well, by setting display to inline-block, and giving it a height as well.
Here, see how you like ’dem apples: http://jsfiddle.net/pSg2D/9/
You should use CSS instead. Using z-index and maybe even float would (atleast should) fix this.
Edit: Always make sure no other styles make it break line!

Two columns text block with an image

I need some help...
How should I do the markup of a layout with two images and a block of text divided in 2 columns with different width, where the 2nd column starts lower than the first one because of one of those images? Here is a sketch of my layout:
I hope I described my problem explicitly enough.
P.S.: Is it possible actually?
CSS3 has a solution, but it is not standard yet and won't work in older browsers here is a link http://www.css3.info/preview/multi-column-layout/.
Possibly the best idea is to use javascript somehow. Put all the text in the first column and test the height then move portions of the text over to the next column until you have equal columns or until the first column is at a desired height.
Another method is to have predefined proportions eg(2/3 in the first column and 1/3 in the second). Then split the text based on the proportions using character count. This won't be exact and you could use a method similar to the one above to find exact width based on overflow properties, but the characters should average out to be the correct length.
This method is pretty simple and would look like
var txt='Column text...';
var len=txt.length;
var chars=Math.floor(len*.67);
//Assuming you want 2/3 of the text in the first column
document.getElementById('col1').innerHTML=txt.substring(0,chars);
document.getElementById('col2').innerHTML=txt.substring(chars);
//Notice that this could split in the middle of a word so you would need to do
//some checking for the nearest space and the change the break to there.
//Also you could then use the previous method to adjust it if you want something really accurate

Finding the first word that browsers will classify as overflow

I'm looking to build a page that has no scrolling, and will recognize where the main div's contents overflow. The code will remember that point and construct a separate page that starts at that word or element.
I've spent a few hours fiddling, and here's the approaches that past questions employ:
1. Clone the div, incrementally strip words out until the clone's height/width becomes less than the original's.
Too slow. I suppose I could speed it up by exponentially stripping words and then slowly filling it back up--running past the target then backtracking slowly till I hit it exactly--but the approach itself seems kind of brute force.
2. Do the math on the div's dimensions, calculate out how many ems will fit horizontally and vertically.
Would be good if all contents were uniform text, ala a book, but I'm expecting to deal with headlines and images and whatnot, which throws a monkey wrench in this one. Also complicated by browsers' different default font preferences (100%? 144%?)
3. Render items as tokens, stop when the element in question (i.e. one character) is no longer visible to the user onscreen.
This would be my preferred approach, since it'd just involve some sort of isVisible() check on rendered elements. I don't know if it's consistent with how browsers opt to render, though.
Any recommendations on how this might get done? Or are browsers designed to render the whole page length before deciding whether a scrollbar is needed?
Instead of cloning the div, you could just have an overflow:hidden div and set div.scrollTop += div.height each time you need to advance a 'page'. (Even though the browser will show no scrollbar, you can still programmatically cause the div to scroll.)
This way, you let the browser handle what it's designed to do (flow of content).
Here's a snippet that will automatically advance through the pages: (demo)
var div = $('#pages'), h = div.height(), len = div[0].scrollHeight, p = $('#p');
setInterval(function() {
var top = div[0].scrollTop += h;
if (top >= len) top = div[0].scrollTop = 0;
p.text(Math.floor(top/h)+1 + '/' + Math.ceil(len/h)); // Show 'page' number
}, 1000);
You could also do some fiddling to make sure that a 'page' does not start in the middle of a block-level element if you don't want (for example) headlines sliced in half. Unfortunately, it will be much harder (perhaps impossible) to ensure that a line of text isn't sliced in half.

Categories

Resources