I have a page with about 10 iframes. Only 1 of these iframes are visible and the index of the visible iframe changes every page reload. The visible iframe only contains a style of display: block, it doesn't contain anything else that I can use to select it like a name or title.
Example:
<div class="container">
<iframe style="display: none; width: 310px; height: 100px; border: 0px;
user-select: none;">
<html>
<body>
<div class="button"/>
</body>
</html>
</iframe> <--- not visible
<iframe style="display: block; width: 310px; height: 100px; border: 0px;
user-select: none;">
<html>
<body>
<div class="button"/> // need to click this!
</body>
</html>
</iframe> <--- visible :)
</div>
My question is how can I select the iframe with the display: block style in puppeteer and then click the button inside it.
I've tried to solve this by getting all the iframes on a page, looping over then and selecting the one with a display style of 'block':
// select all iframes
const Frames = await page.frames();
// loop over iframes and check if iframe display is block or none.
Frames.forEach(async (item, i) => {
const frame = await item.contentFrame();
const showingIframe = await page.evaluate(
() => window.getComputedStyle(frame.querySelector('iframe')).display
);
if (showingIframe === 'block') {
console.log('showing');
// click button
} else {
console.log('not showing');
}
});
You can easily find an element if the styling is very specific. No need to go through all frames for that.
const selector = `iframe[style*="display: block"]`
const visibleIframe = document.querySelector(selector);
console.log({ visibleIframe });
Clicking a button inside that can be done in a lot of ways. Here is a plain javascript solution,
visibleIframe.contentDocument.querySelector(".button").click()
Codesandbox link
Learn more about asterisk in Attribute selector
So I've finally solved this, thank you to #Md. Abu Taher for pointing me in the right direction.
try {
const selector = `iframe[style*='display: block']`;
await page.frames().find((frame) => frame.click(selector, { delay: 8000 }));
} catch (error) {}
What this does it it finds all the iframes on the page. It then finds and clicks on the iframe that matches the selector defined above, this holds down the button for 8 seconds which bypasses StockX captcha (or rather completes it as a user would).
Related
I'm running into an issue where the getElementById() function is unable to get a particular element on the page that has the display: none property applied to it, even though it's visible in the DOM (I can see that the div and its id exists on the final rendered page).
Is there a way around this?
Here's the code:
togglePanel() {
const panelId = this.accordionItem.querySelector("#collapsible-panel");
this.shouldShowAccordion = !this.shouldShowAccordion;
if (this.shouldShowAccordion) {
panelId.classList.remove("collapsed");
}
else {
panelId.classList.add("collapsed");
}
}
"collapsible-panel" is the ID of the div which has display: none applied to it.
setTimeout(() => {
document.querySelector("div[id='collapsiblepanel']").style.display = 'block';
}, 2000)
#collapsiblepanel {
width: 200px;
height: 100px;
background-color: red;
display: none;
}
Following is ana example where I am selecting a div which has the value of display as none. After 2 seconds I am setting up it's display to block.
<div id="collapsiblepanel">
</div>
<html>
<head>
<style>
.inactiveLink {
pointer-events: none;
cursor: default;
}
</style>
</head>
<body>
<p> You have won a prize. Click here within <div id='clock'></div> seconds ...</p>
<script>
var time = 10;
var f = function counttime(){document.getElementById('clock').innerHTML--;}
function stoptime(){cleatInterval(f);}
if(time){
document.getElementById('clock').innerHTML = time;
var h = setInterval(f,1000);
setTimeout(function(){clearInterval(h);
document.getElementById('clock').innetHTML = "Time's up!";
}, time*1000);
}
</script>
</body>
</html>
I'm trying to create a basic webpage, that says "You have won a prize. Click here within 10 seconds ..." when it opens. You have 10 seconds to click "here" to get your prize. After 10 seconds, "here" should be unclickable. I added a CSS part about being unclickable, which is called "inactiveLink". I don't know how i should implement the change of anchor tag after 10 seconds, to JS. (I'm thinking about after 10 sec, a in HTML should be changed to a with id inactiveLink)
You were almost there :)
I would use a class that uses the CSS-rule pointer-events: none and then use JS to add that class to the link after 10 seconds:
const a = document.getElementById('a');
setTimeout(() => a.className = 'unclickable', 10000);
.unclickable { pointer-events: none; }
<a id="a" href="">Hurry up</a>
Use setAttribute to make it unclickable. Maybe make a class called "unclickable" with all of the CSS you want.
You can see this thread for more information on how to set your link so that it won't fire an event upon click. Check the second answer (not the one that the user marked as correct).
The best way to do it is by removing the attribute href removeAttribute("href");.
Note: that pointer-events:none only prevents mouse clicks but if you used the tab key and pressed ENTER over the link it will still be followed.
function myFunction() {
document.getElementById("anc").removeAttribute("href");
}
<a id="anc" href="google.com">Click Me.</a>
<button onclick="myFunction()">Disabler</button>
anchor tags dont have a disabled attribute, but one approach you can take is to style a button like a link. Something link this for example:
const buttonEl = document.querySelector('#target');
const handler = e => {
console.log('Button is still active!');
};
buttonEl.addEventListener('click', handler);
setTimeout(() => {
buttonEl.disabled = true;
}, 2000);
button {
all: unset;
color: blue;
cursor: pointer;
text-decoration: underline;
}
button:disabled {
color: gray;
cursor: not-allowed;
}
<button id="target" type="button">Click the button</button>
I'm trying to make a toggle which works, but every element I click on creates a stack of these showed elements. Instead I'm trying to hide everything and display only element that I clicked on. Now I can only hide it when I click on the same element twice, which is not what I want. I want to click on one and hide previous ones that were showing.
.totalpoll-choice-image-2 is a bunch of images that always has to be shown. They are what the user clicks on to display hidden description under each image. That description shows up when I click on .totalpoll-choice-image-2. There are 5 images with that class. The next image I click on, I want to hide the previous description box.
My code:
jQuery(document).ready(function() {
var element = document.getElementsByClassName("totalpoll-choice-image-2");
var elements = Array.prototype.slice.call(Array.from( element ) );
console.log(elements);
jQuery(element).each(function(item) {
jQuery(this).unbind('click').click(function(e) {
e.stopPropagation();
var id = jQuery(this).attr("data-id");
console.log(this);
//jQuery("#" + id).css({"display": 'block !important'});
//document.getElementById(id).style.setProperty( 'display', 'block', 'important' );
var descriptionContainer = document.getElementById(id);
var thiss = jQuery(this);
console.log(thiss);
console.log(jQuery(descriptionContainer).not(thiss).hide());
jQuery(descriptionContainer).toggleClass("show");
});
})
})
You can attach event handlers to a group of DOM elements at once with jQuery. So in this case, mixing vanilla JS with jQuery isn't doing you any favors - though it is possible.
I threw together this little example of what it sounds like you're going for.
The script itself is very simple (shown below). The classes and IDs are different, but the idea should be the same:
// Assign click handlers to all items at once
$('.img').click(function(e){
// Turn off all the texts
$('.stuff').hide();
// Show the one you want
$('#' + $(e.target).data('id')).show();
})
https://codepen.io/meltingchocolate/pen/NyzKMp
You may also note that I extracted the ID from the data-id attribute using the .data() method, and attached the event listener with the .click() method. This is the typical way to apply event handlers across a group of jQuery objects.
From what I understood based on your comments you want to show only description of image that has been clicked.
Here is my solution
$('.container').on('click', 'img', function() {
$(this).closest('.container').find('.image-description').addClass('hidden');
$(this).siblings('p').removeClass('hidden');
});
https://jsfiddle.net/rtsj6r41/
Also please mind your jquery version, because unbind() is deprecated since 3.0
You can use event delegation so that you only add your event handler once to the parent of your images. This is usually the best method for keeping work the browser has to do down. Adding and removing classes is a clean method for show and hide, because you can see what is happening by looking at your html along with other benefits like being easily able to check if an item is visible with .hasClass().
jsfiddle: https://jsfiddle.net/0yL5zuab/17/
EXAMPLE HTML
< div class="main" >
<div class="image-parent">
<div class="image">
</div>
<div class="image-descr">
Some text. Some text. Some text.
</div>
</div>
<div class="image-parent">
<div class="image">
</div>
<div class="image-descr">
Some text. Some text. Some text.
</div>
</div>
<div class="image-parent">
<div class="image">
</div>
<div class="image-descr">
Some text. Some text. Some text.
</div>
</div>
<div class="clear">
</div>
</div>
EXAMPLE CSS
.image-parent{
height: 100px;
width: 200px;
float: left;
margin: 5px;
}
.image-parent .image{
background: blue;
height: 50%;
width: 100%;
}
.image-descr{
display: none;
height: 50%;
width: 100%;
}
.show-descr{
display: block;
}
.clear{
clear: both;
}
EXAMPLE JQUERY
$(".main").on("click", ".image-parent", ShowDescription);
function ShowDescription(e) {
var $parent = $(e.target).parent(".image-parent");
var $desc = $parent.find(".image-descr");
$(".image-descr").removeClass("show-descr");
$desc.addClass("show-descr");
}
I wanted to scroll to the bottom of the page using vanilla JS, but I encountered a problem. The code below is supposed to scroll to the bottom of the page:
window.scrollTo(0,document.body.scrollHeight);
Whereas all it does is logs "undefined" in the console. Inputting
document.body.scrollHeight
returns an integer 736. Other than that, it doesn't matter what I input into the function's parameters, nothing happens. What more, it only happens on one website. What may matter (not sure) is that the website hides its vertical scrolling bar, even thought it has a really long list of content.
The problem might be that the actuall scroll that you have on the website is not the scroll of the body but a scroll of another element inside that body.
Here is an example:
$('#btn1').click(function() {
window.scrollTo(0,document.body.scrollHeight);
});
$('#btn2').click(function() {
el = $('.a')[0];
el.scrollTop = el.scrollHeight;
});
body {
overflow: hidden;
margin: 0;
padding: 0;
}
div.a {
height: 100vh;
overflow: auto;
}
div.b {
height: 1500px;
position: relative;
}
div.c {
position: absolute;
bottom: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="a">
<div class="b">
<button id="btn1">Scroll body - doesn't work</button><br />
<button id="btn2">Scroll element - will work</button>
<div class="c">This is at bottom of page</div>
</div>
</div>
Note - the usage of jquery is only to make the example shorter.
Put some content in your page o style the body heigth = 1500px for example, then try to execute same code.
Solved. This is what had to be done:
document.getElementsByTagName('body')[0].style.display = "block";
For whatever reason, changing the display to "block" enabled the scrolling using the given code:
window.scrollTo(0,document.body.scrollHeight);
If you will try to type in browser's console like a var a = 5 you also will get undefined. It happens that your example and my did not return anything.
I have a webpage where i am loading a external webpage into div tag using object tag and it is working fine.the content of the webpage is overflowing and hence i need to implement auto scroll feature. I am able to implement the auto scroll feature to div tag but when i use the same logic for autoscrolling the object then it is not working.
Please find below the code
<script type="text/javascript">
$(function () {
var interval = setInterval(function () {
if ($("#siteloader").scrollTop() != $("#siteloader")[0].scrollHeight) {
$("#siteloader").scrollTop($("#siteloader").scrollTop() + 10);
} else {
clearInterval(interval);
}
}, 1000);
});
</script>
and HTML markup is
<body>
<div id="siteloader" style="height: 100px; width: 600px; border: 1px solid #ccc;
overflow: auto">
<object id="objs" height="500px" width="500px" data="http://www.w3schools.com"></object>
</div>
</body>
i am able to scroll the div but i am unable to scroll the contents within object tag.
Please note that i am loading page from external website.
any suggestions??
Thanks