I'm new to javascript and css and I'm trying to develop a chrome extension which when the user clicks on an element of a specific class in the webpage, it automatically clicks also the next 5 elements.
I found that the css selectors of all the elements of that class are identical up to a number, so I tried the following:
for (i = 1; i <= 5; ++i) {
document.querySelector(
'#selector_first_part... > div:nth-child('+
i +
') > selector_second_part).click();
}
The code above works fine when I manually set i.
The problem is that I need to extract "i" from the clicked-on element, and in order to do that I thought that I need to get the css selector of the clicked-on element.
I tried to inject a script to the source code that adds an eventListener to each element of that class, which sends the ID of the clicked-on element, and using the ID i thought that I could extract the css selector. here is the code:
var actualCode = `
var elements = document.getElementsByClassName('someClass');
var onClickFunction = function() {
var id = this.getAttribute('id');
alert("This object's ID is " + id);
};
for (var i=0; i<elements.length; i++) {
elements[i].addEventListener('click', onClickFunction, false);
}
`;
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.remove();
When running this code the alert says "This object's ID is null", meaning that I can't get the css selector using the ID, because it seems that the elements have no ID.
So my question is: how could I click (with JS) the surrounding elements of the clicked-on element?
Thanks!
1st of all, placing your code into a DOM load event like #eytienne already mentioned is used to make sure the page is loaded before attaching your event.
2nd: you should not need to attach several handler, just one click handler on document- then use the target to get the actual element that was clicked, e.g.
const handler = function(e) {
const elem = e.target;
}
document.addEventListener('click', handler, false);
3rd: you don't need an id, just compare all elements, e.g. (in your handler):
const target = e.target;
for (let i=0,elems=document.querySelectorAll(..);i<elems.length;i++) {
if(elems[i] === target) {
... do something ...
}
I did not test the code.. just to give you an idea.
I hope this will help you!
I think you should replace your script manipulation with that:
window.addEventListener('DOMContentLoaded', function(){
// put your actualCode here
});
Look at this ressource in detail (on Mozilla Developper Network, the official documentation):
https://developer.mozilla.org/fr/docs/Web/Events/DOMContentLoaded
I think you did not understand the purpose of an 'id' in the HTML context so discover it (MDN is always a good resource ;) ):
https://www.google.com/search?q=id+mdn
Related
I have the following retrieved from the web page:
next page
the onclick=onClkRdMsg is constantly changing, is there any method to click on the next page button directly?
since the onclick selector is keep changing, and the href=# if not working, sorry for not having code included here.
just want to know how to click on the next page...
casper.then(function (){
this.click("[????='next page']");
});
what is the ????
casper.click("[????='next page']"); invokes a click using a CSS selector. CSS selectors are not capable of matching an element based on its content (text).
It's easy with XPath expressions, though:
var x = require('casper').selectXPath;
...
casper.click(x('//*[contains(text(),"next page")]'));
If you're sure that there is no whitespace around the search text, then you can also use casper.clickLabel():
casper.clickLabel('next page');
You have to check every link on the page for text "next page":
casper.evaluate(function(){
var tags = document.getElementsByTagName("a");
var searchText = "next page";
var found;
for (var i = 0; i < tags.length; i++) {
if (tags[i].textContent == searchText) {
found = tags[i];
found.click();
break;
}
}
})
Based on How to get element by innerText
I'm implementing (through pure JavaScript) something like facebook's message loading. Meaning that if you scroll to the end of the page, new (HTML) content is loaded and added to the end of the page. I get this extra content through Ajax. But when I add this (HTML) to the page, it could mean the page has to load extra images. Is there a way I can figure out when the page has finished loading everything, so including all the new images?
You can add the load event (https://developer.mozilla.org/en-US/docs/Web/Events/load) to the appended elements:
function LOADER_FUNCTION(e) {
console.log("LOADED", e.target);
}
var element = document.querySelector('#parent');
for(i=0; i<element.childNodes.length; i++) {
element.childNodes[i].addEventListener('load', LOADER_FUNCTION);
}
This will call the LOADER_FUNCTION function when the content within that element is ready. Oddly this doesn't seem to work when attached to the parent.
Edit:
Here is a working example. Although this example is not using Ajax (mainly due to CORS issues) it should work under the same conditions. I've used innerHTML to set my DOM in order to demonstrate that this event is not limited to createElement -> appendChild:
(function(){
// This Code Runs after DOMContentLoaded
var element = document.getElementById('parent');
function LOADER_FUNCTION(e) {
document.querySelector('.status').innerText = ("LOADED " + e.target.tagName);
console.log("LOADED", e.target);
}
element.innerHTML = "<img src='http://i.imgur.com/OfSN9oH.jpg'>";
for(i=0; i<element.childNodes.length; i++){
// Attach new event handler
element.childNodes[i].addEventListener('load', LOADER_FUNCTION);
}
})()
<div class='status'></div>
<div id="parent"></div>
Edit 2:
For nested children in append/innerHTML use element.querySelectorAll('*');
https://jsfiddle.net/bckpL9k6/1/
Hi I am adding a iframe dynamically, It displays an image from a server. I need to disable the context menu for this item. In chrome I can inspect element and if I add oncontextmenu="return false" I do get the wanted affect. However I am unable to do this while the page is generated. Here is an example of the working html.
However I can not reproduce this when i frame is being created. Here is my code.
$(window).scrollTop(0);
$('#secVerify').show();
$("#popWaitLoad").modal("hide");
imgLoading.hide();
dvIframe.empty();
//else load deposit data into interface
$("#spanType").text(deposit.DepositType);
$("#spanReference").text(deposit.Reference);
$("#spanAmount").text("R " + deposit.Amount.toFixed(2));
$("#spanDate").text(deposit.DateCreatedOffsetS);
imageID = deposit.Deposit_Doc_imageID;
var url = imageUrl + '/' + deposit.Deposit_Doc_imageID + '/false';
var imgFrame = document.createElement("iframe");
imgFrame.src = url;
imgFrame.frameBorder = '0';
imgFrame.scrolling = 'no';
imgFrame.width = '100%';
imgFrame.height = '100%';
imgFrame.align = 'middle';
imgFrame.id = "iframeImg";
dvIframe.append(imgFrame);
I have tried examples like.
$("#iframeImage").contents().find("img").attr("oncontextmenu", 'return false');
$('#iframeImage img').on('contextmenu', function (e) {
e.stopPropagation();
// Your code.
return false;
});
But because the img element seems to be only created is done after page load it seems to not work. I know disabling the the menu will not help much and I have explained all the other methods of obtaining the image that is still available but the client really wants this.
I have added nocontextmenu to the body tag and it works everywhere except for the iframe.
So let me clarify, My iframe is working like it should however I would like to disable the right click aka context menu on the specific iframe.
I have used setAttribute to set the attributes and targeted a container to appendChild.
function example(){
var target = document.getElementById('container');
var element = document.createElement('img');
element.setAttribute('src', 'http://gopalshenoy.files.wordpress.com/2011/04/product_demos.jpg');
//element.setAttribute('width','100%');
//element.setAttribute('height','100%');
element.setAttribute('id','iframeImage');
element.setAttribute("oncontextmenu","return false;");
target.appendChild(element);
}
// Demo-Snippet use.
window.onload=example;
<!-- Demo Snippet use -->
<div id="container"></div>
If you build more than one element using this function you might find further issues due to duplicated ID's.
ID's are used to target a specific element 'one of' so if you want to build multiple elements I would recommend giving them unique ID's.
I hope this helps. Happy coding!
I have an anchor tag element coming in the html like:
Now in the javascript function, I have written:
function handleEvent(sourceElement, txt) {
console.log(sourceElement);
}
the consoled element is coming as the window in this case.
I tried sourceElement.document.activeElement but it doesnt seem to work in chrome, where it is coming as body element.
I cannot change the structure of the anchor tag to 'onClick' function as this is coming from some other source.
Is there some way to find the calling element in this scenario?
The real answer here is to change the HTML, which you've said you can't do. I'd push back on that if you can. If you're writing the function, and the function name is in the HTML, how is it you can't change the HTML??
But if you really, really can't, you can update the DOM once it's loaded:
var list = document.querySelectorAll('a[href^="javascript:"]');
var x, link;
for (x = 0; x < list.length; ++x) {
link = list[x];
link.onclick = new Function(link.href.substring(11));
link.href = "javascript:;";
}
Live Copy | Live Source
This is fairly naughty, as it uses the Function constructor (which is very much like eval), but if you trust the source of the HTML, that should be okay.
Or of course, if you don't have to use whatever was in the href to start with, just hook up your event handler in the code above and don't use new Function.
try something like this, use jQuery
just select the link tag with your selector
$(function(){
var href = $('a').attr('href');
href = href.replace('javascript:','');
$('a').attr('href','#');
$('a').attr('onclick',href);
})
This is just workaround solution.
If you have access to the js, you could do something like this:
document.addEventListener('DOMContentLoaded', function(){
var link = document.querySelectorAll('a');
link[0].addEventListener('click', function(e){
console.log(e.target);
});
});
With this, you would be just not be doing anything with the inline href event and just be appending your own handler.
And if no other answer here works for you because you can't update the DOM after it's loaded (try doing any of them if you want to modify a squarespace lightbox - not saying it's impossible, but...), here's an out of the box thinking:
Sometimes there will be something hinting where the a href is. So you could use it.
<div class="hint current">
<a href="javascript:handleEvent('.hint')">
In my case, I even knew the hint without needing a parameter, which made things even simpler:
function handleEvent (hint) {
if(!hint) {
hint = $("div.current");
}
hrefElement = $(hint).find('a[href^=javascript]');
}
This of course will make sense if your DOM is constantly being changed by a script you have no access to.
But even if there is nothing hinting on the a href, you still could do something like this:
<a href="javascript:var x=1;handleEvent(1)">
function handleEvent (uniqueId) {
hrefElement = $('a[href^=javascript:var x='+uniqueId);
}
I don't need to write this in jQuery but I'm not versed enough in plain javascript to figure it out. Chris Coyier wrote a nice explanation of what I'm talking about here.
The reason I want to convert it is because I don't need to include an entire jQuery library for this one piece of code. I can save that extra request by using plain old javascript.
This is the example code that I want to convert:
$(document).ready(function() {
$(".featured").click(function(){
window.location=$(this).find("a").attr("href"); return false;
});
});
Here's what I've come up with so far:
document.addEventListener("DOMContentLoaded", function() {
document.querySelectorAll("div.feature").click(function(){
window.location=$(this).find("a").setAttribute("href");
return false;
});
});
One thing which isn't correct in this, as far as I know, are the querySelectorAll, which is looking for just a div element, right? The other thing is the $(this), which I don't know how to translate into plain javascript.
Assuming...
you know the browser support for querySelectorAll and yet you still use it
that addEventListener only works for standards compliant browsers
I believe you meant:
//get all a's inside divs that have class "featured"
var feat = document.querySelectorAll("div.featured a"),
featlen = feat.length,
i;
//loop through each
for(i=0;i<featlen;++i){
//add listeners to each
feat[i].addEventListener('click',function(){
window.location = this.href;
},false);
}
Or you can have the <div> wrapped in <a>. No JS required. It's perfectly valid HTML and browsers do work as intended despite the rule that inline elements should not contain block elements. Just make sure to have display:block on <a> as well as adjust its size.
<a href="location">
<div> content </div>
</a>
You can select with this.querySelectorAll(...):
IE8:
window.onload = function() {
// get all dom elements with class "feature"
var aFeatures = document.querySelectorAll(".feature");
// for each selected element
for (var i = 0; i < aFeatures.length; i++) {
// add click handler
aFeatures[i].onclick = function() {
// get href of first anchor in element and change location
window.location = this.querySelectorAll("a")[0].href;
return false;
};
}
};
IE9 and other current browser:
document.addEventListener("DOMContentLoaded", function() {
// get all dom elements with class "feature"
var aFeatures = document.querySelectorAll(".feature");
// for each selected element
for (var i = 0; i < aFeatures.length; i++) {
// add click handler
aFeatures[i].addEventListener('click', function() {
// get href of first anchor in element and change location
window.location = this.querySelectorAll("a")[0].href;
return false;
});
}
});
=== UPDATE ===
For IE7 support you should add following (untested) script before (also see here):
(function(d){d=document,a=d.styleSheets[0]||d.createStyleSheet();d.querySelectorAll=function(e){a.addRule(e,'f:b');for(var l=d.all,b=0,c=[],f=l.length;b<f;b++)l[b].currentStyle.f&&c.push(l[b]);a.removeRule(0);return c}})()
It is possible that it only supports document.querySelectorAll not element.querySelectorAll.