I need a javascript bookmarklet which can click on a button. The thing is, there are 100+ buttons on the page all with the same value. The name is unique but quite long.
The full name of the element is something like :
actions[http://apps.facebook.com/frontierville/giftaccept.php?next=giftaccept.php&senderId=1%3A1325206719&gh=3a8bfdace76051752a9127d1f9b43872&gift=nails×tamp=1285598414&ref=tab&key=29b15e06ed9d7c00a8870c955ab938cf%24%24cfH1PUUZ%217bZYhg8M-o-XQc%218HHRMcvvyhuf4d%21.64qEvlQe&src=request&aff=gift&crt=nails&signature=6dd3fa03fe88f98b6dcab4faf4c7da94]
The value of every button is Accept and Play.
So. Is there a way to have it click on the button with a specific URL in the name?
Here is the source of the info for one of the buttons (got this from chrome's inspect element feature):
<input value="Accept and Play" type="submit" name="actions[http://apps.facebook.com/onthefarm/giftaccept.php?senderId=1259413693&gift=mysterygift×tamp=1285599906&ref=gift_accept_tab&key=78fcc7de3b36b8f9564262fab506893f%24%24ceK5RVRY61bZYhg8M-o-XQcyL%2CzHccEwEeuj4e-%21-dh0AD0A2AgyScd&signature=32db959ce43f8330cf8fd992fbd53a51&srcapp=FarmVille]">
This should do it...
javascript:var nam=prompt("Give me a URL to look for"); nam="actions["+nam.replace(/\&/g, "&")+"]"; var els=document.getElementsByName(nam); if(els.length == 0) alert("Button not found"); else els[0].click();
It's based on getElementsByName, here it is all spelled out...
var nam = prompt("Give me a URL to look for");
nam = "actions[" + nam.replace(/\&/g, "&") + "]";
var els = document.getElementsByName(nam);
if(els.length == 0)
alert("Button not found");
else
els[0].click();
Here's a rough example of what you might want to do.
var url = 'http://reallylong.facebook.url.from.your.example';
var searchName = 'actions[' + url + ']';
var items = document.getElementsByName(searchName);
if (items.length > 0) {
var myButton = items[0]; // assuming the first item is the correct one
myButton.click(); // programmatically click it
}
if the url is going to change every time, you can find someway to fill the url variable, and use that to generate the element name. This example assumes that element is the only one on the page with that exact name attribute.
This example is pretty rigid and may not work as your bookmarklet if you need to interact with it. What do the other elements look like? Would it be better to look for an element pointing to the giftaccept url or something like that? The script would have a lot more flexibility in a situation like that.
For convenience and compatibility use JQuery selectors:
nameVal = 'actions[http://apps.facebook.com/onthefarm/giftaccept.php?senderId=1259413693&gift=mysterygift×tamp=1285599906&ref=gift_accept_tab&key=78fcc7de3b36b8f9564262fab506893f%24%24ceK5RVRY61bZYhg8M-o-XQcyL%2CzHccEwEeuj4e-%21-dh0AD0A2AgyScd&signature=32db959ce43f8330cf8fd992fbd53a51&srcapp=FarmVille]'
$("input[value='Accept and Play'][name='" + nameVal + "']").click()
Related
This should be pretty easy but I'm struggling.
I have a button that fires a function. I want an alert to fire as well that tells me which page the user was on.
www.whatever.com/thispage1/whatever
www.whatever.com/thispage2/whatever
www.whatever.com/thispage3/whatever
So after my button is clicked, I want an alert that reads back "thispage1" or "thispage2" etc. I do not want the entire URL fed back to me. Is there a way to find text in a url based on its position or number of characters before it starts?
Look at window.location.pathname and use str.slice to extract the bit you want, with str.indexOf to find the indices to start/end at
var top_dir = window.location.pathname.slice(
1,
window.location.pathname.indexOf('/', 1)
);
Maybe this will help you get started. Key players here are window.location.pathname and string.split()
var returnPage = function() {
var urlString = window.location.pathname;
var stringArray = urlString.split("/");
return stringArray[0]; // number == whichever piece of the array you want to get
};
function myFunction() {
alert(returnPage());
}
Imagine I have a loaded HTML page which has been already affected by javascript adding/deleting dynamic elements or new classes/attributes/id to elements while initializing(e.g: original source code [html] tag has no classes, after javascript loads [html] tag has class="no-responsive full-with"). Imagine after that I add/amend some id values manually (through my app). And imagine I need to be able to save in database the original source code (without any amends) but with the id attributes I added manually.
Basically I need to add a given id attribute to an element within the source code of an HTML, loaded through PHP.
Do you guys have any idea of how to do such a thing?
There's no simple solution here. The exact nature of the complex solution will be determined by your full set of requirements.
Updated Concept
You've said that in addition to changing things, you'll also be adding elements and removing them. So you can't relate the changed elements to the originals purely structurally (e.g., by child index), since those may change.
So here's how I'd probably approach it:
Immediately after the page is loaded, before any modifications are made, give every element in the a unique identifier. This is really easy with jQuery (and not particularly hard without it):
var uniqueId = 0;
$("*").attr("data-uid", function() {
return ++uniqueId;
});
Now every element on the page has a unique identifier. Next, copy the DOM and get a jQuery wrapper for it:
var clone = $("html").clone();
Now you have a reliable way to relate elements in the DOM with their original versions (our clones), via the unique IDs. Allow the user to make changes.
When you're ready to find out what changes were made, you do this:
// Look for changes
clone.find("*").addBack().each(function() {
// Get this clone's unique identifier
var uid = $(this).attr("data-uid");
// Get the real element corresponding to it, if it's
// still there
var elm = $("[data-uid=" + uid + "]")[0];
// Look for changes
if (!elm) {
// This element was removed
}
else {
if (elm.id !== this.id) {
// This element's id changed
}
if (elm.className !== this.className) {
// This element's className changed
}
// ...and so on...
}
});
That will tell you about removed and changed elements. If you also want to find added elements, just do this:
var added = $(":not([data-uid])");
...since they won't have the attribute.
You can use the information in clone to reconstruct the original DOM's string:
clone.find("[data-uid]").addBack().removeAttr("data-uid");
var stringToSend = clone[0].outerHTML;
(outerHTML is supported by any vaguely modern browser, the latest to add it was Firefox in v11.)
...and of course the information above to record changes.
Live proof of concept
HTML:
<p class="content">Some content</p>
<p class="content">Some further content</p>
<p>Final content</p>
<input type="button" id="makeChange" value="Make Change">
<input type="button" id="seeResults" value="See Results">
JavaScript:
// Probably unnecessary, but I wanted a scoping
// function anyway, so we'll give the parser time
// to completely finish up.
setTimeout(function() {
// Assign unique identifer to every element
var uniqueId = 0;
$("*").attr("data-uid", function() {
return ++uniqueId;
});
// Clone the whole thing, get a jQuery object for it
var clone = $("html").clone();
// Allow changes
$("#makeChange").click(function() {
this.disabled = true;
$("p:eq(1)").attr("id", "p1");
$("p:eq(2)").addClass("foo");
alert("Change made, set an id on one element and added a class to another");
});
// See results
$("#seeResults").click(function() {
this.disabled = true;
// Look for changes
clone.find("*").addBack().each(function() {
// Get this clone's unique identifier
var uid = $(this).attr("data-uid");
// Get the real element corresponding to it, if it's
// still there
var elm = $("[data-uid=" + uid + "]")[0];
// Look for changes
if (!elm) {
display("Element with uid " + uid + ": Was removed");
}
else {
if (elm.id !== this.id) {
display("Element with uid " + uid + ": <code>id</code> changed, now '" + elm.id + "', was '" + this.id + "'");
}
if (elm.className !== this.className) {
display("Element with uid " + uid + ": <code>className</code> changed, now '" + elm.className + "', was '" + this.className + "'");
}
}
});
});
function display(msg) {
$("<p>").html(String(msg)).appendTo(document.body);
}
}, 0);
Earlier Answer
Assuming the server gives you the same text for the page every time it's asked, you can get the unaltered text client-side via ajax. That leaves us with the question of how to apply the id attributes to it.
If you need the original contents but not necessarily identical source (e.g., it's okay if tag names change case [div might become DIV], or attributes gain/lose quotes around them), you could use the source from the server (retrieved via ajax) to populate a document fragment, and apply the id values to the fragment at the same time you apply them to the main document. Then send the source of the fragment to the server.
Populating a fragment with the full HTML from your server is not quite as easy as it should be. Assuming html doesn't have any classes or anything on it, then:
var frag, html, prefix, suffix;
frag = document.createDocumentFragment();
html = document.createElement("html");
frag.appendChild(html);
prefix = stringFromServer..match(/(^.*<html[^>]*>)/);
prefix = prefix ? prefix[1] : "<!doctype html><html>";
suffix = stringFromServer.match(/(<\/html>\s*$)/);
suffix = suffix ? suffix[1] : "</html>";
html.innerHTML = stringFromServer.replace(/^.*<html[^>]*>/, '').replace(/<\/html>\s*$/, '');
There, we take the server's string, grab the outermost HTML parts (or use defaults), and then assign the inner HTML to an html element inside a fragment (although the more I think about it, the less I see the need for a fragment at all — you can probably just drop the fragment part). (Side Note: The part of the regular expressions above that identifies the start tag for the html element, <html[^>]*>, is one of those "good enough" things. It isn't perfect, and in particular will fail if you have a > inside a quoted attribute value, like this: <html data-foo="I have a > in me">, which is perfectly valid. Working around that requires much harder parsing, so I've assumed above that you don't do it, as it's fairly unusual.)
Then you can find elements within it via html.querySelector and html.querySelectorAll in order to apply your id attributes to them. Forming the relevant selectors will be great fun, probably a lot of positional stuff.
When you're done, getting back the HTML to send to the server looks like this:
var stringToSend = prefix + html.innerHTML + suffix;
Disclaimer: I am fully aware that the id attribute is for unique IDs. In my case, when the ajax request takes longer than usual it can glitch, causing two same chat messages. I am also aware that there are similar questions out there like this, but I have been unable to find one that solves my issue.
This is what I want to do:
Are there any duplicate IDs inside the div chat_log?
What are they?
Delete all the duplicates
Making sure that the original one is still there.
I've tried using the following code:
$('[id]').each(function () {
var ids = $('[id=' + this.id + ']');
if (ids.length > 1 && ids[0] == this) {
$(ids[1]).remove();
}
});
But I'm not sure how I can adapt that method to my situation, nor am I sure if it would be possible.
How can you ensure that something is unique? Let's say you have a bunch of vegetables (cucumbers, turnips, pizzas etc.) You want to ensure colour uniqueness, making sure that any colour only appears once. How'd you do it?
What I'd do is make a list. I'd go through every vegetable, and inspect its colour. If the colour is already on the list, we'll remove that vegetable from the bunch. Otherwise, we leave it as-is and add its colour to our list.
Once that logic is understood, all we need is to convert it to code! What a fantastically trivial thing to do (on paper, of course.)
//assumes $elem is the element you're deleting duplicates in
//create the ids list we'll check against
var ids = {};
//go over each element
var children = $elem.children();
for ( var i = 0, len = children.length; i < len; i++ ) {
var id = children[ i ].id;
//was this id previously seen?
if ( ids.hasOwnProperty(id) ) {
$( children[i] ).remove();
}
//a brand new id was discovered!
else {
ids[ id ] = true;
}
}
//done!
This is the very simple, plain logic version. You can make much fancier ways with some weird sizzle selectors, but this should get you started.
Demo (without jquery): http://tinkerbin.com/qGJpPsAQ
Your code should work but it only removes the second element that has the same ID, try this:
$('[id]').each(function() {
var $ids = $('[id=' + this.id + ']');
if ($ids.length > 1) {
$ids.not(':first').remove();
}
});
http://jsfiddle.net/3WUwZ/
Here is a simplified example of what i'm working with, working around preexisting code:
Basically I have 2 divs I want to hide/show in multiple places(stage 1, stage 2, stage 3,etc), as so:
var blue_div = "#Blue";
var red_div = "#Red";
var blue_stage = "#Blue" + count;
var red_stage = "#Red" + count;
Adding insult to injury the div's exist elsewhere on page and are hidden. Need to pull the content into another div for each stage. So i'm using .prepend() to grab the content, as so:
var blue_html = $(blue_div).html();
var new_div = "#new_div";
$(new_div).prepend(blue_html);
$(new_div).attr('id', blue_stage); //Changing the id based on the stage
That last part is really whats throwing me...As now I'm trying to use the new_div without first ending the script so it's not yet in the DOM...
if ($(blue_stage).is(':hidden')) {
$(blue_stage).show()
$("#cancel").bind("click",function(){
$(blue_stage).hide()
}
}
I've seen a lot done with Window setTimeout() as well as setinterval and .queue(). But my attempts have all failed. Hopefully my example wasn't confusing, any help at all is appreciated!
I think you can do something like this:
var $new_div = $('<div id="' + blue_stage + '"></div>');
which will allow you to edit the element directly so you can do things like:
$new_div.prepend(blue_html);
to change the id you do:
$new_div.attr('id', blue_stage)
and note when your setting the id like this you don't need the "#" as the other answer mentions
Remember that you use the hash-mark # when selecting, but when setting as an ID on a node, you just use the identifier without this mark. So this line:
$(new_div).attr('id', blue_stage); //Changing the id based on the stage
Equates to this:
$(new_div).attr('id', '#Blue' + count);
But should perhaps be like this:
$(new_div).attr('id', 'Blue' + count);
(without the hashmark).
Hopefully your problem is as easily solved! Good luck!
Please forgiving if the title is a little non-descriptive. Here is what im doing. Im making dynamic textboxes in a table using javascript. For example i add one row to the table, give the textbox a name for instance tname, i want to make each textbox unique so i add a row number to the end of it, so the textbox name is tname1, next would be tname2...etc. Now I want to create another function to loop through this table to get all of the values. Here is the code im using to get the value of the textbox below. I didnt put the for loop b/c I know that the loop works, b/c i got the correct number of rows.
txt = document.getElementById('tname' + a)
alert(txt.value)
I know that there is a function that you put around this: ('tname' + a) to let javascript know that your concatenating it together b/c i did it before just cant remember the function. If any can help, it would be very much appreciated
If you assigned the id (not name) then dirty pure JavaScript work around is:
var a = 1;
while (true) {
var id = 'tname' + a;
var txt = document.getElementById(id);
if (txt == null)
break;
alert("value of " + id + " is: " + txt.value);
a++;
}
This will keep looking for elements, until it can't find any - hope this makes sense.
You need to use ID and name. For example,
<input type="text" name="tname1" />
should be
<input type="text" name="tname1" id="tname1"/>
Use JQuery. It simplifies tasks like this:
$('input[type="text"]').map(function(){
return (this.value.length > 0) ? this.value : null;
}).get().join(',');
Working demo: http://jsfiddle.net/AlienWebguy/wLteQ/
Have you tried:
var els = document.getElementsByName(...);
// Or if you only focusing on newer browsers:
var els = document.querySelectorAll(..);
// els is now a HTMLCollection / NodeList
console.log(els[0].value);