So I figured I'd get a little bit of Javascript practice and work on my first Google Chrome extension. I'm making an extension that, when the user clicks the "Like" button on Facebook, if the post they click on is older than a certain threshold, then it prompts them to make sure they indeed meant to click "Like" on the post (to prevent accidental likes when stalking).
I have basic functionality down where if the user clicks like it prompts them to make sure they meant to hit like, and if they didn't meant to, they can cancel the like at that point. However, now I'm trying to add detection of whether a post is of a certain age or not, to only prompt when the post is old.
My source for what I have right now is located here:
https://github.com/mathur/StalkingCondom
Essentially, Facebook stores this data in a timestamp, and I want to know how to access the timestamp just from the post where the user is currently "liking" and not any of the other timestamps on the page.
Below is my code that runs when the document is loaded:
$(document).ready(function(){
$( ".UFILikeLink" ).click(function(e) {
if (confirm("Are you sure you want to like this?")) {
// like was intended, continue with usual behavior
}
else {
// like was not intended, lets stop that like!
e.stopPropagation();
e.preventDefault();
}
});
});
The timestamps are stored between abbr tags like below:
<abbr data-utime="1421210082" data-shorten="1" class="_5ptz timestamp livetimestamp">10 mins</abbr>`
Every post has its own div with certain unique ID.
Basically I need to wrap the entire UFILikeLink click function in an if statement where if the date is older than a certain date then execute the click function right? How would I make it so the Javascript finds the timestamp only within that one unique div?
Is anyone willing to point me in the right direction? Is this even feasibly possible? Thank you so much for your time!
First of all: Facebook's timeline gets updated via AJAX requests every time you reach the bottom, so adding a listener to $(".UFILikeLink") will only work on the first few links (loaded at the beginning). If you want it to work for ALL the links, you'll have to add a listener to the <body> element.
So you will use addEventListener('click', func(){...}, true) to add a listener for the click event, and set useCapture=true (last argument). With useCapture set as true you can prevent the events before they reach the target element and stop them when necessary. Then, inside the event listener you will check if the clicked element has class UFILikeButton, and, if so, continue.
Now, before writing down anything, you need to make some corrections considering the following facts:
The "Like" text that the user clicks is actually a <span>, and does not have the class "UFILikeLink", but its parent does. Here is the structure of a like link:
<a class="UFILikeLink" href="#" role="button" aria-live="polite" title="Like this" ...>
<span data-reactid=".27.1">Like</span>
</a>
You don't exactly know where the <abbr> element is located, so you'll need to search for it: using .parents(".userContentWrapper") you'll find the post body container, which contains the <abbr> element, then using .find("abbr") you'll finally get to it. Here is the full code:
var timestamp = +$(e.target).parents(".userContentWrapper").find("abbr").attr("data-utime");
*The + (plus) converts the string to a number
If the user clicks on "Unlike" instead of "Like", you should not display the prompt, so it is useful to check for the text contained inside the clicked element, like this:
$(e.target).text() == 'Unlike';
Facebook timestamps are in seconds, but JavaScript timestamps are in milliseconds. To compare them you have either to multiply the first one or divide the second one by 1000.
Here is the final code, to make things easier I created likeLink, which is the link with class "UFILikeLink", and likeSpan, which represents the text contained in the link (the one the user really clicks).
document.body.addEventListener('click', function(e) {
var likeLink = $(e.target.parentElement),
likeSpan = $(e.target),
timestamp, oldTimestamp;
// If the clicked element is not the Like button, just stop the function
if (!likeLink.hasClass("UFILikeLink")) return;
// If the users clicks to UNLIKE, you don't need to check
if (likeSpan.text() == 'Unlike') return;
timestamp = +likeLink.parents(".userContentWrapper").find("abbr").attr("data-utime");
// Set a limit of one month ago (2592000 seconds = 30 days)
oldTimestamp = +new Date()/1000 - 2592000;
// If the post is older than one month...
if (timestamp < oldTimestamp && !confirm("Are you sure you want to like this?")) {
// like was not intended, lets stop that like!
e.stopPropagation();
e.preventDefault();
}
}, true);
The above code will prompt the "Are you sure?" message for posts older than one month. You can edit the check variable to set it to older or newer posts.
Get a reference to the parent div however you want. If you know the Id for the div, that's an option. If they're all inside a container, maybe you can get it by ID and iterate over its children. You'd have to provide the markup to get a more specific answer on that part. Once you have that reference to the div, you can get the child element by tag name (assuming there's only one abbr tag inside, or at least there's are recognizable pattern). Here's an example of the call you could make to do it.
document.getElementById('parentDivId').getElementsByTagName('abbr')[0].getAttribute('data-utime');
Breaking that out into parts,
document.getElementById('parentDivId') gets a reference to the element with the specified ID, in this case a <div id="parentDivId">
.getElementsByTagName('abbr')[0] finds all child elements within the div that are <abbr> tags, and returns them in an array. The [0] part gets this first element from the array.
.getAttribute('data-utime') gets that attribute from the selected abbr element.
Is that clear?
See here for reference to the selectors you have available in vanilla javascript - http://www.w3schools.com/jsref/dom_obj_document.asp. If you're using jquery (looks like this question is tagged that way) it has its own set of selectors with additional flexibility.
Related
I have a modal with an accordion in it. There is an anchor tag for each image on the page that can open the modal window. Inside the modal, the accordion has slide switches where the user can choose to turn on or off a value for that image.
The undesired behavior occurs after one input has changed on a specific image. I am receiving the value of the input values that were previously changed as well.
What I would like to see is for each image to have it own values, that is, the values that were changed specific to that image. I shouldn't see the values from any other image. In addition, if I change the value of a specific image to
true, I don't want to see that value set to true for any other image. I hope this all makes sense. I'm not very savvy with JavaScript but I've tried to explain as best I can.
This is what the JavaScript looks like
$(".glyphicon-tags").on('click', function(){
var iid = $(this).data('iid'); // this is the imageId
$(".onoffswitch ").on("click", function(){
var tid = $(this).data('tid'); // this is the tagId
alert(iid + ' ' + tid);
});
});
Using
$(".onoffswitch ").off("click").on("click", function(){
should fix it.
The way you've got it now, every time glyphicon-tags is clicked, you just keep on adding extra event handlers for "onoffswitch" and never removing the old ones. Next time onoffswitch is clicked, it runs all the defined event handlers. Setting an event handler on an element doesn't remove the old one (unless you're running IE6 or something), it adds an extra one to the existing list of handlers.
The "off" method removes previously defined event handlers on an element. See http://api.jquery.com/off/ for more details of the options you can pass in etc.
I have a .pdf document that contains custom links which run Javascript code.
There is no issue with the actual functionality of the working portion of the JS, but I do have one formatting/display problem that I havent been able to solve:
Is it possible to write JS that will alter the appearance of individual links as they are clicked?
I know I can programmatically change the appearance of all links on a page by looping through the doc.getLinks result and applying formatting changes to each element of the getLinks array. But I don't know how to refer to a specific link, as/after it's clicked, either by referencing that link's index location within the getLinks array, or by referring to it by any other name, handle, etc.
I would think that this is probably possible to do, but I'm at a loss.
Thanks in advance for any pointers!
EDIT: One thing to clarify...I can do everything I need to do for a single button. That is, I can manually find the button name, and manually enter the JS code to change the appearance of that particular button. To do this, I need to physically look up the name of the button using a few mouse clicks, and then hard code that button's name in my JS getField command. This requires different code for each and every button.
Is it possible to accomplish the same function using the same code for each and every button?
My ultimate objective is to be able to reproduce this function on a series of .pdf files that will, jointly, have thousands of individual buttons. So any manual component of this process will make implementation impractical.
I should have originally phrased the question in terms of, is it possible to write JS code that can automatically detect the name of the button which is calling the code? (ie, how would I implement a self-referential feature for a generic button?)
As wished by the OP…
When a script should refer to the field on which it is running, the field object to use is event.target.
An example:
You have a button which, when clicked, should change the width of the border between 1 and 3. The mouseUp event would containt this piece of code:
if (event.target.lineWidth == 1) {
event.target.lineWidth = 3 ;
} else {
event.target.lineWidth = 1 ;
}
Or another example: when the number in the calculated text field is negative, it should be in red, otherwise in black:
In the Format event of that field, you would add:
if (event.value*1 < 0) {
event.target.textColor = color.red ;
} else {
event.target.textColor = color.black ;
}
And that should give an idea on how to use event.target.
I'm using the following spell checking javascript. The button that opens the spell checker is defined as button and if a icon, image or text is given the matching id, when this is clicked the spell checker opens.
I want to be able to call the spellchecker directly e.g. onclick="openChecker();" i even tried _openChecker() but cannot seem to call the correct function.
https://raw.github.com/LPology/Javascript-PHP-Spell-Checker/master/spellcheck.js
Can anyone help?
Thanks
The ID property should be unique in the first place so you should not have other elements with the same ID - one of the reasons is what happens to you, you get events triggered when elements with the same ID are clicked. You should fix this and if you do have elements that require the same identificator, you should use a class instead. As for your question you could do something like this:
$("selector").on("click",function(){
//your code here
});
I have a form which is using a select list to jump around my site. This is currently using onclick window.location so user selects the page and presses go and it goes to that page.
I now need to add a small text box for the user to type in a code (say 123456) and then when they click go, it should go to the url selected, but with the [CODE] being the number entered in the box. I discovered jquery replaceAll so it gave me the idea to have this in the select html:
http ://jumptothispage.com/parts/p[CODE]/edit
http ://jumptothispage.com/jobs/j[CODE]/edit
When you press go, it would replace all [CODE] in that html with the code entered and then jump to that page selected, e.g.
http ://jumptothispage.com/parts/p123456/edit
http ://jumptothispage.com/jobs/j123456/edit
I am already using jquery on my site so makes sense to try and utilize that again. I'd appreciate a pointer and or other suggestions instead.
Thanks,
Paul.
A workaround: Store the code in a cookie, so at least it's not visible to every person who looks at the URL bar. Then in every onclick, fit it into the URL to send the user to the "right" page.
Or, have your select option's value literally read CODE, which your onclick interprets to mean "The user hasn't set the code yet." When the user types in the code, store it in a variable (in the example below, realcode), and you can then do this:
$('select#navigation option').each(function(idx, el) {
$(el).attr('value', $(el).attr('value').replace(/CODE/, realcode));
});
Newbie question...
The objective:
I intend to have an HTML text input field as a kind of command line input.
An unordered HTML list shows the 5 most recent commands. Clicking on one of the last commands in this list should populate the command line input text field with the respective command (in order to re-execute or modify it).
An unordered HTML list contains a result set. Clicking on an ID in this list should bring the respective ID into the command line input text field.
In HTML (DHTML):
Works as expected: when clicking on the the link the command line input text field is populated with a recent command.
<li>here would be one of the recent commands</li>
In Javascript file:
Doesn't work as expected: when clicking on the the link the command-line-input-text-field gets populated with the respective value (as it should), BUT then it seems like the full HTML page is being reloaded, the text input field and all dynamically populated lists become empty.
function exec_cmd(cli_input_str) {
// a lot of code ...
// the code that should provide similar behavior as onclick=... in the DHTML example
$('.spa_id_href').click(function(){document.getElementById('cli_input').value = document.getElementById('cli_input').value + this.firstChild.nodeValue;});
}
Now the Question:
Besides a potential Javascript (syntax) error, what could cause the browser to reload the page?
In both cases, you do nothing to cancel the default function of clicking on a link.
In the plain HTML example, the link to the top of the page is followed.
You don't specify what the href attribute for the second example looks like, but whatever it is, it will be followed.
See http://icant.co.uk/articles/pragmatic-progressive-enhancement/ for a good explanation of event cancelling and good event design. See http://docs.jquery.com/Tutorials:How_jQuery_Works for some jQuery specific guidance.
Change
$('.spa_id_href').click(function(){...
to
$('.spa_id_href').click(function(evt){...//notice the evt param
and in the function, call
evt.preventDefault();
It seems that you just follow the link target URL. That is because you do not prevent the default click action:
e.preventDefault(); // `e` is the object passed to the event handler
// or
return false
Alternatively, you can set up a href starting with #, or not use <a> element at all (use <span style="cursor:pointer"> instead) — if it’s not a real link of course.
It's basically related to event cancelling...
Try this:
try { (
e || window.event).preventDefault();
}
catch( ex )
{
/* do Nothing */
}
While the other answers here make excellent points about canceling events, you will still run into problems if your JavaScript contains errors which prevent your event-canceling code from being run. (As might be the case if you're, say, debugging your code.
As an additional precaution, I strongly recommend you not use href="#" on links which only trigger scripts. Instead, use the void operator:
...
The reason for this is: when the event is not canceled, the browser will attempt to load the URL supplied by the href attribute. The javascript: "protocol" tells the browser to instead use the value of the accompanying code unless that value is undefined. The void operator exists explicitly to return undefined, so the browser stays on the existing page — with no reload/refresh — allowing you to continue debugging your script.
This also allows you to skip the entire event-canceling mess for JS-only links (though you will still need to cancel events in code attached to links which have a "fallback" URL for non-JS clients).