Watir::Browser#execute_script and "Element no longer valid" - javascript

I'm writing some automation for a website of ours in Internet Explorer (it has to be IE :< ) and I ran into some issues with execute_script. I need to move a vertical splitbar over 200px so it doesn't move certain elements off the page, making them unclickable. To do this I figured I would use the Watir::Browser#execute_script functionality. The idea would be to change the style tag to the correct coordinates. Unfortunately I haven't been able to get it to work due to "Element is no longer valid" errors. Here are the two cases I tried and their respective errors.
First, I tried just getting the style attribute (the one I need to change) via a javascript script.
script = <<-JS
return arguments[0].style
JS
browser.execute_script(script, aw.watir.div(class: 'x-vsplitbar'))
This gives me Uncaught exception: Element is no longer valid
I also tried changing the element's tag as well.
element = aw.watir.div(class: 'x-vsplitbar')
style = element.style.gsub('200', '400')
script = "return arguments[0].style = '#{style}'"
browser.execute_script(script, element)
This just gave me a sweet error JavaScript error (Selenium::WebDriver::Error::JavascriptError)
The script in this example comes out to:
return arguments[0].style = 'HEIGHT: 897px; WIDTH: 5px; POSITION: absolute; LEFT: 400px; TOP: 50px'
Not sure what I'm doing wrong here, I followed this guide.
Another solution would be to use Watir to simulate the dragging action needed but I couldn't figure out how to drag the bar to the right.

Related

How to target / apply styles to an image loaded from Javascript

I installed a SSL trust logo onto my website – the following code is what displays the logo:
<script language="JavaScript" type="text/javascript">
TrustLogo("https://www.(mywebsite).com/comodo_secure_seal_76x26_transp.png", "CL1", "none");
</script>
I needed it to be fixed on the bottom left corner of my page, so after a lot of trial and error I settled with the following code:
img:not(main img) {
position: fixed;
bottom: 0;
left: 0;
The problem is, this isn't really targeting the specific image that needs to be targeted. The bigger problem is that this does not work on any other browser other than the browser I had originally tested (Safari). (Maybe it's because the 'img' tag is not appropriate targeting?)
How can I target this logo? (If not through CSS, how can I make it fixed?)
Safari (the CSS works here)=>
Chrome (CSS does nothing)=>
This worked for me:
Do not use img to target the logo – use one of the image's attrributes to be as specific as possible.
Try something as simple as the src attribute:
[src="https://www.(mywebsite).com/comodo_secure_seal_76x26_transp.png"]
You can also use a node inspector to view more useful information to help you pinpoint the image.

Replace Text/Image URL with CSS [duplicate]

This question already has answers here:
Replace the directory of an image src, using Javascript
(2 answers)
Replace images source for all images
(3 answers)
Closed 5 years ago.
I am trying to make a custom style for the stylish plugin to use for the Eve Online forums. I am attempting to resize the avatar image because it was too small for my liking. However it's using a low-quality image and it looks too grainy when resized, so I am trying to figure out how to use the larger image by replacing part of the text, or replacing the url (whatever is easier). In the image, the only difference a piece of text that shows the size.
See:
meta.eveonline.com/erika_mizune/45/2168_1.png
meta.eveonline.com/erika_mizune/90/2168_1.png
So essentially the 45 (original) needs to be replaced with the 90 in order to look less grainy.
URL to Post: https://meta.eveonline.com/t/avatar-size-category-adjustment/9032
Stylish Plugin: https://userstyles.org/styles/144974/avatar-category-adjustment
My code to resize the image is this:
.topic-avatar img.avatar
{
height: 75px;
width: 75px;
border-radius: 0;
}
.topic-avatar
{
width: 75px !important;
}
I tried to search before posting but I'm not finding anything that will work for what I need.
Thanks!
Edit 1: I attempted to switch to tampermonkey to use JS as suggested but is not working. Below is the origional code:
<div class="topic-avatar">
<a class="trigger-user-card main-avatar" href="/u/Erika_Mizune"
data-user-card="Erika_Mizune"> <img alt="" width="45" height="45"
src="https://cdn-enterprise.discourse.org/eveonline/user_avatar/meta.eveonline.com/erika_mizune/45/2168_1.png"
title="Erika_Mizune" class="avatar"></a>
<div class="poster-avatar-extra"></div>
</div>
And the script I have in tampermonkey:
var imagelist = document.getElementsByClassName("avatar");
imagelist.foreach(function(element) {
element.src = element.src.replace("/45/", "/90/");
});
Edit 2: After trying to use debugging in the console I got the error that .foreach is not a function and attempted to try the following as well:
Try 1:
var imagelist = document.getElementsByTagName("img");
imagelist.foreach(function(element) {
element.src = element.src.replace("/45/", "/90/");
});
Try 2:
var imagelist = Array.from(document.getElementsByClassName('avatar'));
imagelist.foreach(function(element) {
element.src = element.src.replace("/45/", "/90/");
});
Try 3:
var imagelist = Array.from(document.getElementsByTagName('img'));
imagelist.foreach(function(element) {
element.src = element.src.replace("/45/", "/90/");
});
All of these attempts have returned the same error in console that .foreach is not a function.
I think the javascript solution is the right way to go.
It's really hard to say what's wrong with just a few lines of js from tampermonkey. Is it possible to show the complete files? Or post an example on jsfiddle or something?
It's easy to debug this kind of issue yourself in Chrome Inspector, by typing "debugger" in your code and opening the Source tab in Chrome Inspector (F12 button in Chrome). The inspector will stop at that line and you can see the values of different variables. For example:
First, open Chrome Inspector in Chrome browser. Then load the page with the debugger line:
var imagelist = document.getElementsByClassName("forum_image_class");
debugger;
imagelist.foreach(function(element){
element.src = element.src.replace("/45/", "/90/");
}
The browser will stop on the debugger line. Type 'imagelist' into the console and hit enter to see its current value. It might be empty, in which case the getElementsByClassName isnt retrieving anything. Which might be happening for a few different reasons. Or the imagelist array might get populated but the replace() isnt working as expected. Is it possible for you to figure out which is happenng and report it here?
ALSO: be careful with .replace(). You have to escape certain characters with a backslash and you should know what those special characters are. In this case you may or may not need to escape the forward slashes.
Try this? Add background: url(meta.eveonline.com/erika_mizune/90/2168_1.png) no-repeat !important; to your img CSS.
.topic-avatar img.avatar {
height: 75px;
width: 75px;
border-radius: 0;
background: url(meta.eveonline.com/erika_mizune/90/2168_1.png) no-repeat !important;
}
.topic-avatar {
width: 75px !important;
}
It isn't possible to change html content with CSS in the way you're describing. I'd recommend using Javascript to change the src of the <img> tag. Do something like
var imagelist = document.getElementsByClassName("forum_image_class");
imagelist.foreach(function(element){
element.src = element.src.replace("/45/", "/90/");
}

Google Map API doesn't work when DOCTYPE declared in Chrome and Firefox

I have this weird problem where my Google Maps API script doesn't work, no map is rendered, when I declare a DOCTYPE.
Without a DOCTYPE I get the following warning, but it works and a map is rendered:
Resource interpreted as Other but transferred with MIME type undefined.
I have no real clue to what is wrong, but I hope some wiz here might!
Here you can see the script in action without DOCTYPE:
[LINK REMOVED SINCE QUESTION IS ANSWERED]
...and here it is with DOCTYPE declared as HTML5:
[LINK REMOVED SINCE QUESTION IS ANSWERED]
JavaScript source is pretty long, but you can find it here:
[LINK REMOVED SINCE QUESTION IS ANSWERED]
But I've made it publicly available at http://snipt.org/yZgm2 if anyone care!
Thank you for your time!
UPDATE 1:
So, it seems like my JavaScript wasn't the problem. But the div-element had no height or width to begin with, and for some reason it works different with or without DOCTYPE.
So new question!
Why does the following code part not work when I have declared a DOCTYPE?
var mapElement = document.getElementById(mapOptions['mapid']);
mapElement.style.width=mapOptions['width'];
mapElement.style.height=mapOptions['height'];
UPDATE 2:
Thanks to both #fivedigit and #duncan for pointing out the CSS problem. Simply adding the measurement unit solved it all!
mapElement.style.width=mapOptions['width']+'px';
mapElement.style.height=mapOptions['height']+'px';
The difference is that the doctype declaration makes the browser go into standard mode, rather than quirks mode. And that's where a little bug in your JavaScript acts up.
The map is created in both instances, but when the doctype has been declared, the map's height is 0, and the width is set to its default (100%).
You have this bit of code where you set the width and height of the map:
if(mapOptions['width'] !== false){
mapElement.style.width=mapOptions['width'];
}
if(mapOptions['height'] !== false){
mapElement.style.height=mapOptions['height'];
}
You forgot to specify the unit there, and in standards mode, that style rule will then be dropped. Change the code to this to make it work:
if(mapOptions['width'] !== false){
mapElement.style.width=mapOptions['width'] + 'px';
}
if(mapOptions['height'] !== false){
mapElement.style.height=mapOptions['height'] + 'px';
}
You probably need to do something about the CSS for the div that the map will be in. Try adding something like this:
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0; padding: 0 }
#map1 { height: 100% }
</style>

How to have a div scrolled to the bottom automatically

I am making a chat-like interface which can be seen here (best viewed in Chrome right now):
http://qas.im/web/sms.php
The temporary username:password is temp_guest:password
My problem is that when you click one of the chats, it doesnt automatically scroll to the bottom when I use this code:
$(".messages").attr({ scrollTop: $(".messages").attr("scrollHeight") });
What could be wrong? The messages div has a css of:
.messages {
height:400px;
overflow: auto;
}
For people who are wondering: Page isnt HTML validated yet but I will be cleaning it up soon. Most of the page is auto-generated which is challenging to make the code look pretty ;P
If you are using jQuery 1.6 or later, use prop instead of attr.
Working example: http://jsfiddle.net/FishBasketGordo/PNwj3/
I found two issues.
The first is that you were trying to set all .message DIVs to the height of the first DIV, so if the first DIV was hidden, it would never work.
The second was that jQuery's attr function is only for node attributes.
This method works better, and scrolls all the divs correctly:
$(".messages").each(function(idx, node) { node.scrollTop = node.scrollHeight; });
Alternatively, you can improve performance by using this selector:
$(".messages:visible").each(function(idx, node) { node.scrollTop = node.scrollHeight; });
Which works on visible message nodes.

Firefox and Chrome give different values for offsetTop

I am trying to position an span element (let us call it "the tooltip span") relative to a input field. To do this, I am wrapping the tooltip span and the input field in another span element (let's call it "the wrapper span") that has position: relative. Then I set position: absolute on tooltip span. This makes the tooltip span position itself relative to the wrapper span but not being part of the page flow - not taking up any space. This is exactly what I want.
Then, using javascript, I set the position of the tooltip relative to the position of the input element. Since the input element can be shaped differently on different pages (script should be globablly applicable), I am using its offsetTop and offsetLeft properties to calculate its position relative to the wrapper span.
However, I am noticing inconsistencies between browsers here. In Firefox, IE6, 7, 8, it works as expected. But in Chrome and Safari the reported offsetTop seems, well, incorrect.
To prove this, I created the test page below:
<html>
<head>
<style type="text/css">
span { font-size: 8px; position: relative; top: 0; left: 0; border: 1px solid red }
</style>
</head>
<body>
<span id="wrapper">
<input id="foo" name="foo" type="text">
</span>
<script type="text/javascript">
document.write("<br>Offset parent: " + document.getElementById("foo").offsetParent.id);
document.write("<br>Offset top: " + document.getElementById("foo").offsetTop);
</script>
</body>
</html>
and loaded it in Firefox and Chrome. Both browser report the wrapper span as its offsetParent, but for Firefox the offsetTop is -8 and for Chrome it is 2. Visually the page renders the same in both browsers.
This gives me a headache, because I cannot just hack in a different offset that I always apply when someone is using Chrome, because if I change the font size, the offsetTop will not change, and my script will break.
Is this a bug? Can I solve this differently?
You Can try using
$(window).load
instead of
$(document).ready
because Explorer and Chrome sets proper offsets only after images have been fully loaded.
I've been having the same problem as you and I realized that (in my case) the thing that was messing up the offset().top value in chrome, was having one or more images without the "height" attribute above the element.
Before
<img src="/images/foo.jpg" />
offset.top() was 100 in Chrome
offset.top() was 150 in Firefox and IE7 (beleive or not, it worked just fine in IE!)
After
<img src="/images/foo.jpg" height="50" width="50" />
offset.top() is 150 in both Firefox, IE7, AND CHROME.
Notice the the difference was 50px, which is actually the same as the image height.
Since I was developing a JQuery plugin, i tryed to collect all the images that had their width and height attributes undefined, and manually setting their size with .width() and .height(), but it didn't work, because Chrome returned 0 for both functions. So, i guess the problem with offset.top() actually relies on that. If JQuery is triying to get te offset.top() value by accumulating the "above" element's height, and one of those elements it's an image with no specified height, "0" will be added to that sum, and therefore the top value will be missing those "ignored" heights.
PS: Sorry for my english, it's been a long time since i wrote such a long text in this language!
Use jQuery. DOM differences between browsers is one of the things it excels at.
Put you code into a window.onload function. I recall having issues when attempting to work with the dom directly from a <script> during page load in firefox, and webkit tends to be slightly more willing to give a sane DOM at such points.
This is just based on prior issues i've encountered, i'm not sure if it's applicable to your case.
I ran into the same problem, and jQuery's position() function was reporting the same as the offset() function. Ultimately it turns out that even waiting for the document to be ready didn't work for me. I had to check offset() later in the flow (in my case, in my handler that is fired on a window.scroll event).
When I try this test code below, on page load, I get different figures for Firefox + Chrome. Once it loads, however, I can press 'd' and I get the same figure for both browsers.
// this produced different results on Chrome + Firefox (Chrome was wrong!)
$(document).ready(function () {
var x = $('#some-div-on-your-page').position().top;
alert("On load, offset is "+x); // Chrome + Firefox report diff figures
$(window).keydown(function(e, r) {
k = e ? e.keyCode : event.keyCode;
if(k == 68) { // press 'd'
var x = $('#some-div-on-your-page').position().top;
alert("Now the offset is "+x); // ...but this is consistent
}
});
}
Hope this helps.
I was experiencing the same problem, and tried adding to my function
$(document).ready(function(){});
and it worked in both Chrome and Firefox
If you get "0" in chrome, see if you are targeting an empty element like "a". It needs to wrap something in order to return the correct offset.
It could be related to the different border/margin values for the HTML and body elements that browsers set by default.

Categories