<a href="javascript:void(0)" class="PrmryBtnMed"
id = "VERYLONGTEXT"
onclick="$(this).parents('form').submit(); return false;"><span>Dispatch to this address</span></a>
If I was to give instructions to a human, I would say:
look for a <span>Dispatch to this address</span> link; if it appears click it. (if there is more than one such link (for example there are two) just click the first one (or any of them)
I am using Greasekit, so I am looking to do this using JavaScript.
Thank you!
Updated: Now checks contents of element
var el = document.querySelector(".PrmryBtnMed"); //should only return first one
if (el && (el.textContent.trim() == 'Dispatch to this address')) {
el.click();
}
Have a look at the querySelector and textContent for more information
I also added a JsFiddle for you: http://jsfiddle.net/NrGVq/1/
A different approach is to search the whole page, in case it's not inside the matched element
var inPage = document.documentElement.innerHTML.indexOf('text to search') > 0,
el = document.querySelector(".PrmryBtnMed");
if (inPage && el) el.click();
Related
I am wanting something similar to this person, except the element I want to match might not be a direct sibling.
If I had this HTML, for example,
<h3>
<span>
<b>Whaddup?</b>
</span>
</h3>
<h3>
<span>
<b>Hello</b>
</span>
</h3>
<div>
<div>
<img />
</div>
<span id="me"></span>
</div>
<h3>
<span>
<b>Goodbye</b>
</span>
</h3>
I would want to be able to do something like this:
var link = $("#me").closestPreviousElement("h3 span b");
console.log(link.text()); //"Hello"
Is there an easy way to do this in jQuery?
EDIT: I should have made my specification a little bit clearer. $("#me") may or may not have a parent div. The code should not assume that it does. I don't necessarily know anything about the surrounding elements.
var link = $("#me").closest(":has(h3 span b)").find('h3 span b');
Example: http://jsfiddle.net/e27r8/
This uses the closest()[docs] method to get the first ancestor that has a nested h3 span b, then does a .find().
Of course you could have multiple matches.
Otherwise, you're looking at doing a more direct traversal.
var link = $("#me").closest("h3 + div").prev().find('span b');
edit: This one works with your updated HTML.
Example: http://jsfiddle.net/e27r8/2/
EDIT: Updated to deal with updated question.
var link = $("#me").closest("h3 + *").prev().find('span b');
This makes the targeted element for .closest() generic, so that even if there is no parent, it will still work.
Example: http://jsfiddle.net/e27r8/4/
see http://api.jquery.com/prev/
var link = $("#me").parent("div").prev("h3").find("b");
alert(link.text());
see http://jsfiddle.net/gBwLq/
I know this is old, but was hunting for the same thing and ended up coming up with another solution which is fairly concise andsimple. Here's my way of finding the next or previous element, taking into account traversal over elements that aren't of the type we're looking for:
var ClosestPrev = $( StartObject ).prevAll( '.selectorClass' ).first();
var ClosestNext = $( StartObject ).nextAll( '.selectorClass' ).first();
I'm not 100% sure of the order that the collection from the nextAll/prevAll functions return, but in my test case, it appears that the array is in the direction expected. Might be helpful if someone could clarify the internals of jquery for that for a strong guarantee of reliability.
No, there is no "easy" way. Your best bet would be to do a loop where you first check each previous sibling, then move to the parent node and all of its previous siblings.
You'll need to break the selector into two, 1 to check if the current node could be the top level node in your selector, and 1 to check if it's descendants match.
Edit: This might as well be a plugin. You can use this with any selector in any HTML:
(function($) {
$.fn.closestPrior = function(selector) {
selector = selector.replace(/^\s+|\s+$/g, "");
var combinator = selector.search(/[ +~>]|$/);
var parent = selector.substr(0, combinator);
var children = selector.substr(combinator);
var el = this;
var match = $();
while (el.length && !match.length) {
el = el.prev();
if (!el.length) {
var par = el.parent();
// Don't use the parent - you've already checked all of the previous
// elements in this parent, move to its previous sibling, if any.
while (par.length && !par.prev().length) {
par = par.parent();
}
el = par.prev();
if (!el.length) {
break;
}
}
if (el.is(parent) && el.find(children).length) {
match = el.find(children).last();
}
else if (el.find(selector).length) {
match = el.find(selector).last();
}
}
return match;
}
})(jQuery);
var link = $("#me").closest(":has(h3 span b)").find('span b').text();
I'm creating button which allows to enter post section. I'm checking if the body has class 'logged-in'. If test is false I want to create div container for message " You have to logi in" and append it to my section. My problem: Everytime when I click this button, new node is appended.
- How to invoke handler only once ?
if( !isOnline ) {
e.preventDefault();
var divForLog = document.createElement('div'),
linkElement = document.createElement('a');
linkElement.setAttribute('href', 'http://domain/login');
linkElement.text = "log in"
divForLog.innerHTML = "You have to ";
divForLog.appendChild(linkElement);
document.getElementById('last_questions').appendChild(divForLog);
}
There are several potential solutions, but I'll only list a couple here.
"Global"
Create a variable var loginShown in the scope where the handler is created. Then, change the ! isOnline check to ! isOnline && ! loginShown in the if statement, and set loginShown = true once you've appended the div.
Fiddle the DOM
Depending on the other content of #last_questions you can simply test whether or not the login element has already been appended using:
if ( ! document.getElementById('last_questions').querySelector('div > a[href="http://domain/login"]' ) ) {
...
}
Failing that, you can do as #NewToJS mentioned in the comments and add an attribute to the parent (once the div has been appended) which you can test for, such as an ID or data- attribute.
Unbind the Event
Easier if you're using jQuery, as mentioned by #Pawel you can simply unbind the event once the div has been appended. Probably the cleanest solution, but also trickier to implement. It also depends what else the handler is doing.
Try to set an attribute id to your div (container in my example) and when the user click check if the element with id already exist in document, if not add it :
if( !isOnline && document.getElementById('container').length==0) {
e.preventDefault();
var divForLog = document.createElement('div'),
linkElement = document.createElement('a');
linkElement.setAttribute('href', 'http://domain/login');
linkElement.text = "log in"
divForLog.innerHTML = "You have to ";
divForLog.appendChild(linkElement);
divForLog.setAttribute('id', 'container'); //Add id attribute
document.getElementById('last_questions').appendChild(divForLog);
}
Hope this helps.
If you're using jQuery something you could do(from the documentation .one | jQuery).
$("#button" ).one( "click", function() {
var divForLog = document.createElement('div'),
linkElement = document.createElement('a');
linkElement.setAttribute('href', 'http://domain/login');
linkElement.text = "log in"
divForLog.innerHTML = "You have to ";
divForLog.appendChild(linkElement);
document.getElementById('last_questions').appendChild(divForLog);
});
However another way I could think of would be to use jQuery's
$('#last_questions').html(divForLog);
Update
If thats not an option(most likely, as the #last_questions div may contain other stuff), you can create a <div id="log-in-alert"></div> which will live inside the #last_questions and only replace the html in this
Hope I was able to help??
I try to write a script based on JavaScript for replacing the current selected anchor element with it's inner HTML.
You can also find a simple running example in JSFiddle. To run the example, click on the first link, and the click the button.
So, for example, if I have the following HTML:
<p>
Wawef awef <em>replace</em> <strong>me</strong>
falwkefi4hjtinyoh gf waf eerngl nregsl ngsekdng selrgnlrekg slekngs ekgnselrg nselrg
<a href="http://www.anothersite.com/>replace me</a> klserng sreig klrewr
</p>
and I like when I click on some of the two anchors to remove the anchor with it's inner HTML. This mean, that if I click on the first anchor element, and click the appropriate button to replace the anchor the result should be like that:
<p>
Wawef awef <em>replace</em> <strong>me</strong> falwkefi4hjtinyoh gf waf eerngl
nregsl ngsekdng selrgnlrekg slekngs ekgnselrg nselrg <a href="http://www.anothersite.com/>replace me</a>
klserng sreig klrewr
</p>
My JavaScript code for this functionality is the following:
// Start tracking the click event on the document
document.addEventListener(
'click',
function(event)
{
// If right click, return
if(event.button == 2)
{
return;
}
// Get the current clicked document element
var link = event.target;
while(link && !(link instanceof HTMLAnchorElement))
{
link = link.parentNode;
}
// Get the element with ID wpf-remove-element-now
var clickedLink = document.getElementById("wpf-remove-element-now");
// If the element exists
if(clickedLink !== null)
{
// By executing this code, I am ensuring that I have only
// one anchor element in my document with this ID
// Remove the id attribute
clickedLink.removeAttribute('id');
}
// If ther is no link element
if(!link)
{
// Disable my "unlink" button
editor.commands.customunlinkcmd.disable();
// and return
return;
}
event.preventDefault();
event.stopPropagation();
// If the user has clickde on an anchor element then
// enable my "unlink" button in order to allow him to
// to replace the link if he like to.
editor.commands.customunlinkcmd.enable();
// Set the id attribute of the current selected anchor
// element to wpf-remove-element-now
link.setAttribute('id', 'wpf-remove-element-now');
}
);
var $unlink_button = document.getElementById('unlink');
$unlink_button.addEventListener(
'click',
function(event)
{
// Get the element with ID wpf-remove-element-now
var link = document.getElementById("wpf-remove-element-now");
// Create a new text node that contains the link inner HTML
var text = document.createTextNode(link.innerHTML);
// Make the replacement
link.parentNode.replaceChild(text, link);
}
);
Everything until now is correct, appart of the replacement of the link. I have try the above code, but the result I get is like the following one:
Wawef awef <em>replace</em> <strong>me</strong> falwkefi4hjtinyoh gf waf eerngl
nregsl ngsekdng selrgnlrekg slekngs ekgnselrg nselrg replace me klserng sreig klrewr
I mean the anchor is replaced with the text form of the inner HTML and not with the HTML form of the inner HTML.
So the question is, how can I do this kind of replacement.
You're creating a text node, so whatever you put in it will be interpreted as text. Instead, since you have the replacement tags predefined, you should create actual DOM elements to replace it with. Something like this could work: JSFiddle
var em_elem = document.createElement('em');
em_elem.appendChild(document.createTextNode("replace"));
var strong_elem = document.createElement('strong');
strong_elem.appendChild(document.createTextNode("me"));
var container_span = document.createElement('span');
container_span.appendChild(em_elem);
container_span.appendChild(strong_elem);
// Make the replacement
link.parentNode.replaceChild(container_span, link);
The answer was much simpler that I thought. I placed the solution below for anybody that need an equivalent solution :) :
$unlink_button.addEventListener(
'click',
function(event)
{
// Get the element with ID wpf-remove-element-now
var link = document.getElementById("wpf-remove-element-now");
// By this code you replace the link outeHTML (the link itself) with
// the link innerHTML (anything inside the link)
link.outerHTML = link.innerHTML;
}
);
Here you can find the running solution : JSFiddle
Note: The inspiration for this solution found in the web page.
I am using GreaseKit (so JavaScript)
Step #1 Look for string & Step #2 Click button
When this HTML page loads, if either of the following :
Only 3 Left or
Only 2 Left or
Only 1 Left
appears in a table cell AND a button with class="PrmryBtnMed" is present in that very same cell, then click the button using el.click();
Can we just look inside the <tr> tags?
If not, an alternative approach might be to just click the first button that appears immediately underneath, or after the desired string.
update: thanks to #Bergi, it seems we can just use:
var LookInCells = document.getElementsByTagName('tr');
About that button: which attribute to look for?
the bit of html looks like: <span>Send me this item</span>
So, thinking about attributes of the button
These will always be the same:
class="PrmryBtnMed"
<span>Send me this item</span></a>
These will always vary, so might as well ignore:
where the link points to (e.g. a href="/gp/wine/taste-next/")
the id will always be 'id = "product-B00123456"'
I'm having a go at this based on the kind guidance of #Bergi!
var LookInCells = document.getElementsByTagName('tr');
var MyString = ['Only 3 Left', 'Only 2 Left', 'Only 1 Left']
for(var i = 0;i < LookInCells.length;i++){
}
var inPage = document.documentElement.innerHTML.indexOf(MyString) > 0,
// el = document.querySelector(".PrmryBtnMed");
el = document.getQuerySelectorAll("td:last-child a.PrmryBtnMed")
if (inPage && el) el.click();
I'm looking to find the id of the previous button. It is pretty far away - lots of table rows, tables, divs, etc. between the target and the button but I thought this would still work:
alert( $(this).prevAll("input[type=button]").attr('id') );
Unfortunately this returns alerts 'undefined'. Help?
function getPrevInput(elem){
var i = 0,
inputs = document.getElementsByTagName('input'),
ret = 'Not found';
while(inputs[i] !== elem || i >= inputs.length){
if(inputs[i].type === 'button'){
ret = inputs[i];
}
i++;
}
return (typeof ret === 'string') ? ret : ret.id;
}
That probably isn't the most efficient solution, but it's the only one I can think of. What it does is goes through all the input elements and finds the one right before the one you passed into the function. You can use it like this, assuming you're calling it correctly and this is the input element:
getPrevInput(this);
Demo
That kind of lookup might be expensive. What about doing a select for all your input[type=button] elements, and traversing that array until you find the element matching your id. Then you can simply reference the array index - 1 to get your answer.
Is the previous button a sibling of the current button? If not, prevAll() won't work. The description of prevAll():
Get all preceding siblings of each element in the set of matched elements, optionally filtered by a selector.
Depending on your DOM structure, you can use a combination of parents() and then followed by find().
This function looks up all input[type=button] elements and uses the jQuery index function to find your current element in this group.
If it could be found and there is a previous element it is returned.
$.fn.previousElem = function(lookup){
var $elements = $(lookup),
index = $elements.index(this);
if(index > 0){
return $elements.eq(index-1)
}else{
return this;
}
}
HTML:
<div><div><div><div>
<input type=button id=1 value=1 />
</div></div></div></div>
<div><div><div><div>
<input type=button id=2 value=2 />
</div></div></div></div>
JS:
alert ($("#2").previousElem('input[type=button]').attr('id'))
http://jsfiddle.net/SnScQ/1/
Here's a different version of Amaan's code, but jqueryfied and his solution wasn't looking for a button. The key to the solution is that jQuery returns the elements in document order, as do document.getElementsByTagName and similar functions.
var button = $('#c');
var prevNode;
$("input[type=button]").each(function() {
if (this == button[0]) {
return false;
}
prevNode = this;
});
alert(prevNode && prevNode.getAttribute('id'));
http://jsfiddle.net/crFy6/
have you tried .closest? ...
alert( $(this).closest("input[type=button]").attr('id') );