4

I'm a total newbie with JS, and I'm trying to click on this button:

<a class="simplebutton" href="javascript:void(0);">find</a>


The XPath of this button is: /html/body/div[5]/div/span[2]/a, and a snapshot of the target page can be seen at this Fiddle.

This is what I've tried, but it doesn't work. (I'm using the function getElementsByClassName which I got from http://code.google.com/p/getelementsbyclassname/):

document.getElementsByClassName('simplebutton').submit();
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
Giorgio
  • 1,603
  • 5
  • 29
  • 52

2 Answers2

6

Here is a complete script that does that. It uses jQuery for the :contains() selector.

Update: Modified script to account for reported AJAX.

// ==UserScript==
// @name     _Click on a specific link
// @include  http://YOUR_SERVER.COM/YOUR_PATH/*
// @require  http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @require  https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant    GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a major design change
    introduced in GM 1.0.
    It restores the sandbox.
*/

//--- Note that contains() is CASE-SENSITIVE.
waitForKeyElements ("a.simplebutton:contains('follow')", clickOnFollowButton);

function clickOnFollowButton (jNode) {
    var clickEvent  = document.createEvent ('MouseEvents');
    clickEvent.initEvent ('click', true, true);
    jNode[0].dispatchEvent (clickEvent);
}

Note: in some cases the contains() term can trigger falsely. For example, if there is an <a class="simplebutton">unfollow</a> button.
Here's one way to prevent false clicks. Modify the clickOnFollowButton function like so:

function clickOnFollowButton (jNode) {
    if ( ! /^\s*follow\s*$/i.test (jNode.text() ) ) {
        /*--- If the node contains anything but "follow" (surrounded by 
            optional whitespace), don't click it.
        */
        return false;
    }
    var clickEvent  = document.createEvent ('MouseEvents');
    clickEvent.initEvent ('click', true, true);
    jNode[0].dispatchEvent (clickEvent);
}

Several things:

  1. getElementsByClassName() returns a list or "collection" of elements. You can't just .submit() its result like that. .submit() is for single elements.

  2. Since this is a link .submit() won't work. .click() will often work, but often not -- when a link is empowered by an event listener (which must be the case for this question).

    The clickEvent code, given above, works in almost all cases.

  3. The page code you gave does not have any link, with class="simplebutton" and text containing find!

  4. What Browser are you using? Which Greasemonkey version? And what OS?

  5. Find and use an appropriate javascript reference and an appropriate DOM reference. The reference listed in the question is for a library that is not standard and not included in your script (most likely).

  6. Use the CSS path, its much easier than XPATH, for this kind of thing. Firebug will show you the CSS path for a given element.
    jQuery uses CSS selectors/paths, as does document.querySelector() (a non jQuery approach).

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • Thanks for your efforts! I really appreciate. Sadly your code doesn't work as expected. For sure it's my fault because I'm giving wrong informations since I'm not an expert. In my opinion the button I want to click is loaded after the initial page has been loaded so GM can't identify it. If you have an instagram account you can log in in this site: http://ink361.com, I'd want to click the follow button. – Giorgio Sep 04 '12 at 06:50
  • 2
    That's a pretty big omission. You should probably upvote both answers to compensate. Anyway, I don't have an instagram account, but I changed the script to where it works with AJAX. It will fire no matter when that button appears. Just make sure it's `follow` and not `Follow` (case is critical for that). – Brock Adams Sep 04 '12 at 07:34
  • Thanks for your support man! Now it's working as expected: sorry if my question wasn't as complete as it should be! – Giorgio Sep 04 '12 at 08:31
  • Just another quick question here: I have waitForKeyElements ("a.simplebutton:contains('follow')", clickOnFollowButton);. This will fire if the word 'follow' is contained, however this will fire also for the word 'unfollow'. How to make it fire only in the first case? – Giorgio Sep 06 '12 at 09:09
  • 1
    Updated the answer to account for that. – Brock Adams Sep 06 '12 at 21:30
2

You need to use the method click rather than submit. You can use submit when you want to submit a form.

getElementsByClassName also returns an array of elements, you need to retrieve the one you want and then call click on it.

document.getElementsByClassName('simplebutton')[0].click();​

http://jsfiddle.net/kLDde/

Matt Zeunert
  • 16,075
  • 6
  • 52
  • 78
  • @Giorgio Forgot about selecting an element from the array. You can't click an generic data structure, but you can click an HtmlElement. – Matt Zeunert Sep 03 '12 at 18:56
  • `.click()` does not working everywhere, since you already caught the event, why you need call `submit()`? – Eric Yin Sep 03 '12 at 18:56
  • Now I'm using: document.getElementsByClassName('simplebutton')[0].click(); But still not clicking – Giorgio Sep 03 '12 at 18:57
  • @Giorgio Did you try the jsfiddle? In your example in the question nothing should happen when the link is clicked (you've disabled that by adding href="javascript:void(0);"). There might be cross-browser issues, what browser are you using? – Matt Zeunert Sep 03 '12 at 18:58
  • Maybe the content of the page is loaded dinamically with ajax? – Giorgio Sep 03 '12 at 18:58
  • Yes, it's working in Jsfiddle but not in the original website. – Giorgio Sep 03 '12 at 18:59
  • @Giorgio Can you link to an example or create a jsfiddle? When is the code that clicks the link run? It needs to be after the link has been placed on the page. – Matt Zeunert Sep 03 '12 at 18:59
  • Can't we use the xpath instead? I don't know if that class name is the first occurrence in the page... – Giorgio Sep 03 '12 at 19:03
  • @Giorgio I thought finding the element was not the problem. Can you create a jsfiddle so that I can have a look? – Matt Zeunert Sep 03 '12 at 19:25
  • @Giorgio Just the parts needed to replicate the problem. – Matt Zeunert Sep 03 '12 at 19:29
  • The part needed is here: /html/body/div[5]/div/span[2]/a – Giorgio Sep 03 '12 at 19:31