How can I log a hyperlink click? - javascript

I have a hyperlink which I need to log when it's clicked.
I created a small prototype, and the problem is repeatable by creating a new MVC 2 Web app project.
Add
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
to the Site.Master file.
And
public ActionResult LogSomething()
{
string doNothing = DateTime.Now.ToString();
return new EmptyResult();
}
to the HomeController.cs file
And
<p>
<a id="lnkTestPost" href="/home/about">Test Post</a>
<script type="text/javascript">
$("#lnkTestPost").click(function() {
$.post("/home/LogSomething");
});
</script>
</p>
in Home/Index.aspx
Put a break point in the LogSomething() action method in the HomeController.
But when I run it, sometimes the breakpoint is hit, other times it isn't.
I'm assuming it's not being hit due to the actual link sending the browser to another page, but shouldn't the post be made before the link is fired?
Is there anyway I can ensure the logging code is fired?
Please note; adding the logging functionality in the link target is not an option.
EDIT: The original hyperlink is actually to a custom protocol for an app installed on the user PC. So the link is to something like "myapp:myArgs". I didn't mention that in order to keep things simple, unfortunately, since none of the answers really apply to me, I now think it's necessary to mention.

If I were doing it, I would probably do what, eg, Google does and setup a URL which logs then redirects. For example:
stuff
<script>
$("a:href").each(function(){
this.attr("href", "/log?url=" + encodeURIComponent(this.attr("href")));
});
</script>
Then /log handler would do something like:
def log(request):
target_url = request.GET["url"]
log_link(target_url)
return HttpRedirect(target_url)
You'd need to put some thought into dealing with external links (eg, how you want to handle http://example.com/log?url=http://evil.com/)… But that's a solvable problem.
Also, for bonus points, you could swap the URL as the link is clicked (this is what Google does in their search results), so the mouse-over link-preview looks correct.

Alternatively, you could do what Google Reader does, and put a "from url" in each link:
<script>
$("a:href").each(function(){
this.attr("href", this.attr("href") + "?from=" + encodeURIComponent(window.location));
// (note: this exact code won't handle links which already have GET vars…)
});
</script>
Then use some middleware to log the "from" in inbound requests.
This has the disadvantage that it won't be able to log clicks going to another domain… But that might be alright.

I think the browser could easily navigate to the URL before logging the click. How about:
<p>
<a id="lnkTestPost" href="#">Test Post</a>
<script type="text/javascript">
$("#lnkTestPost").click(function() {
$.post("/home/LogSomething", function(data) {
// only tell the browse to navigate away once its logged
window.location = '/home/about';
});
});
</script>
</p>

An approach that I have seen used by many sites, including google, is to have a "redirector" page, so all the links go through that page/controller, you log it, then from there you can redirect them

How 'bout an optional "log" parm on each page that is included as part of the links so you don't have to have any Javascript at all? Granted, each page could be logging something from the referrer page, but it shouldn't care, since you could have it just pass off whatever's in the log parm to the logging infra and go on.

Related

Page reloads when clicking anchor element

I'm working on a web application which is a traditional aspx (asp.net) web forms app but has had some angular 6 apps incorporated into it.
I've been tasked with fixing a bug that causes the browser to refresh when clicking on an anchor element with a href="#".
I'm not sure what's causing the whole page to reload.
Strangely when I open dev tools in Chrome, choose the network tab and select disable cache the page only refreshes the first time I click a link and any other subsequent clicks work fine. This might be to do with the fact that after the first time I click it the browser url now contains the # at the end of it.
I know this seems a bit random but I wondered whether anyone had any theories on what may cause the reload in the first place.
It's hard to tell what could be causing this without seeing any code. The most common solution I've used when I get this behavior is a prevent default. You can do something like
<a href="#" (click)="$event.preventDefault()">
Or if you already have a click event then pass in $event as a parameter to your function then preventDefault in the function you are calling. This would look like:
Html
<a href="#" (click)="someFunc($event)">
and in your ts:
someFunc(event) {
event.preventDefault();
// rest of your code here
}
This answer is related to the question and it's the first one that comes up in Google so I hope this is useful.
I have some external web components that use regular anchor tags with hrefs that point to routes in my angular app. Clicking the href causes a full page reload. This is because I'm not using routerLink - but, in my case, I can't.
So, my work around is:
#HostListener('window:click', ['$event'])
onClick(e: any) {
const path = e.composedPath() as Array<any>;
const firstAnchor = path.find(p => p.tagName.toLowerCase() === 'a');
if (firstAnchor && !firstAnchor.hasAttribute('routerlink')) {
const href = firstAnchor.getAttribute('href');
this.router.navigateByUrl(href);
e.preventDefault();
}
}
Depending on your application, you might need to make some other checks e.g. is the target _blank, is it an external url etc.
change your a tag code as below
A Tag
this will invoke yourClickEvent(); without page reload
check the stackblitz here stackblitz
If you don't want to reload the page use $event.preventDefault()
<a href="#" (click)="$event.preventDefault()">
Try using debug tools to select the element, then click Event Listeners and then the Click event to see what is listening. Perhaps you can track it down that way.
You could also simply paste this into the console to trigger a break, and then click any of the offending elements:
['unload', 'beforeunload'].forEach(function (evName) {
window.addEventListener(evName, function () {
debugger; // Chance to check everything right before the redirect occurs
});
});
source: Break when window.location changes?
As you are using angular routes, try to use this notation:
<a [routerLink]="['./']" fragment="Test">
As explain by this comment: https://stackoverflow.com/a/38159597/4916355
use href="javascript:void(0);"
The reason you’d want to do this with the href of a link is that normally, a javascript: URL will redirect the browser to a plain text version of the result of evaluating that JavaScript. But if the result is undefined, then the browser stays on the same page. void(0) is just a short and simple script that evaluates to undefined.
Use [routerLink] instead of using href = "", and use click event to call your calling method in the typescript file.
ex:
// downloading the file based on file name
<a [routerLink]="'file://' + 'path'" (click)="downloadFile(templateDocument.fileName)">{{downloadDocuments.fileName}}</a>
Since you have mentioned the web app is asp.net webforms, can you please let us know
Whether the link is asp.net hyperlink control. If so,
AutoEventWireUp could cause the link to be automatically submitted:
Please have a look at this link
If you do have asp.net server controls on the page, then you could disable by setting
#Page AutoEventWireup="false"
For the entire project, this can be disabled by setting in web.config:

how to put non removable credit link

I want to put a non removable credit link on my blogger templates but I don't know how. I have seen many templates using it but they are revealing their secrets.
All of them obfuscate their codes.
This is the below that I want to hapen.
Site name
When they change the example.com - they will be redirected to example.com
when they remove or change the class "credit" they will be redirected..
They are putting their javascript code before .
Yes, You can but you have to use a JQuery in your template for this.
<script type='text/javascript'>
//<![CDATA[
$(document).ready(function()
{
var aa=$("#mycredit").val();
if (aa == null) {
window.location.href = "http://www.example.com/";
};
$("#mycredit").attr("href","
http://www.example.com/");
});
//]]>
</script>
And after adding above code, add the below code in your footer where you want to write your credit link...
<div id='#mycredit'>
Designed By <a href='http://www.example.com/' id='#mycredit'>Example Company</a>
</div>
Replace the URL from above to your on in both codes. Now for safty, Encrypt the above JQuery with your Blogger Template other JQuery using Javascript Obfuscator
As an aside, in your example code "credit" is an ID and not a class.
If you are selling or giving other people HTML code and associated JavaScript and CSS for use on their own site, it is impossible to prevent them from changing or adding to it. Whilst you could obsfucate a click event handler that directs to your site, which may be nontrivial to locate and remove, it does not help in circumstances where the link has simply been removed from the HTML by the user - or hidden using CSS. Testing for all possible methods of hiding the link (positioning, visibility, display, opacity, text-indent, colour, height/width etc.) will be onerous and a losing battle.
Assuming the user did simply change the credit link to point to their own site, and could not find and locate the click handler that directs visitors to your site instead - it would be easy for them to provide their own click handler which directs to their site and stops propagation to stop your handler being called.
To avoid the user removing the link, or changing the URL, in your HTML template you could add it to the page using JavaScript but - even if you could prevent the user from removing this code through obsfucation - any CSS rules applied to the page will still be applied, allowing the user to hide it, and it could be trivially removed from the DOM using their own scripts. Search engines also will most likely not see the link, even if left unchanged, as JavaScript may not be evaluated by visiting bots.
In summary, by all means seek credit for your work, and leave a link in your template - but there is no technical way you can guarantee that it will not be changed or removed once run on the sites of your end users. The best method would probably be to require that the link remains, and points to your site, in the license for use of the template.
You can do this using jquery. There is a easy way to add this.
$(document).ready(function(){
//Let's first setup the redirect
function redirect(){
window.location.assign('http://www.example.com');
}
//which things we got to check
function check(){
if($('#credits').length === 0){
redirect();
}
else if($('#creditlink').length === 0){
redirect();
}
else if($("#creditlink").attr("href") !== "http://www.example.com"){
redirect();
}
else if($('#creditlink').text() !== "Site name"){
redirect();
}
}
//execute the function on page load
check();
//excute the function at the intervals of 5 seconds.
setInterval(function () {check()}, 5000);
});
This program will better help you to add non removable credit link. But for which you need to add the HTML somthing like this
<div id="credits">
<a id="creditlink" href="http://www.example.com">Site name</a>
</div>
Reference: http://themedaddy.net/lets-learn-to-protect-your-work-with-non-removable-credit-links/

History object back button with iframes

I'm having problems with history object and iframes in javascript/html5. I wrote a simple project to describe my problem:
http://dktest.evermight.com/
It's a page with an iframe and a next button. Every time you click next, it loads a new page with an incrementing counter. However, clicking the browser back button doesn't do what I want it to do. Let me explain the problem by breaking this post up into the following sections:
What I'd like to achieve
Undesired results in current project
Post all my code
1. What I'd like to achieve
I want the user to:
Open a new window and go to http://dktest.evermight.com/
Click next page and see a redbox fade in, and to see the url http://dktest.evermight.com/count.html?count=0 appear in both the iframe AND the browser's address bar
Click next page again and see http://dktest.evermight.com/count.html?count=1 in the iframe and browser's address bar
Click browser's back button ONCE and see http://dktest.evermight.com/count.html?count=0 in both the iframe and the browser's address bar
Click browser's back button ONCE and see http://dktest.evermight.com/ in the browser's address bar AND see the red box fade out
2. Undesired results in current project
With my code at http://dktest.evermight.com/, it's currently not performing steps 4 and steps 5 correctly. When I perform step 4, the iframe shows http://dktest.evermight.com/count.html?count=0 but the browser address bar shows http://dktest.evermight.com/count.html?count=1. I have to press the browser's back button again to make the browser address bar show http://dktest.evermight.com/count.html?count=0. When I perform step 5, the red box fades out which is great, but the address bar is still showing http://dktest.evermight.com/count.html?count=0. I have to press back again to make the address bar show http://dktest.evermight.com/.
3. Post all my code
My code is pretty straight forward. You can view source on http://dktest.evermight.com/. I will also post here for convenience.
index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
var count=0;
function clicknext()
{
$('#container').fadeIn();
$('#iframe').attr('src','count.html?count='+count.toString());
$('html title').html(count);
history.pushState({blahblah:'whatgoeshere?'},'i dont know what goes here either','http://dktest.evermight.com/count.html?count='+count);
count++;
}
function hideContainer()
{
$('#container').fadeOut();
var closeurl = 'close.html';
if($('#iframe').attr('src') != closeurl )
$('#iframe').attr('src', closeurl);
}
$(document).ready(function(){
hideContainer();
});
</script>
</head>
<body>
<div id="container" style="display:none; background:red;">
<!-- IMPORTANT
When DOM first created, the iframe.src MUST BE initialize.html
I have some code that I need to fire on that page before the rest
of this document starts
-->
<iframe id="iframe" src="initialize.html"></iframe>
</div>
<input type="button" onclick="clicknext()"; value="next page" />
</body>
</html>
close.html
<!DOCTYPE html>
<html>
<script type="text/javascript">
parent.hideContainer();
</script>
</html>
count.html
I CAN NOT modify the contents of count.html. In my real project, count.html is actually a youtube video, which is on a server I can't directly access.
<html>
<body>Youtube video at url <script type="text/javascript">document.write(location.href);</script></body>
</html>
initialize.html
Perform application specific functionality
Can anyone correct my code to achieve the results of step 4 and step 5 as described in section 1?
UPDATE
Ok, I'm appreciating the problem a bit more based on some experiments I'm doing.
Experiment 1: I tried changing the line:
$('#iframe').attr('src','count.html?count='+count.toString());
to
$('#iframe')[0].contentWindow.location.replace('count.html?count='+count.toString());
This allowed me to perform step 4 correctly. Apparently, contentWindow.location.replace() will not create an entry in the history object. However, this caused some other issues related with the contents of count.html, which is actually a page to youtube/vimeo content. The youtube/vimeo content REQUIRES that you load information via the attr('src') approach instead of .contentWindow.location.replace(). So perhaps the solution is to find a way to make attr('src') NOT create an entry with the history object?
Experiment 2 Another possible solution I tried was changing the order of the attr('src') and history.pushState() call. I tried calling attr('src') first then history.pushState() second, and also history.pushState() first then attr('src') second. But in both cases, when I push the browser's back button, it is the iframe content that goes back first. So there's no way for me to capture pass myself a message via the history object to do a "double back", since information in the history object is available LAST in the sequence of events.
Experiment 3 I also tried working with History.js. It did not do anything to solve my problems above. From what I could tell, it worked exactly like the regular history object.
Does anyone have any thing else I can try? Or suggest modifications to any of the experiments above? I'm going to explore Experiment 1 further as a separate stack overflow question.
I create a new iframe and destroy the iframe when loading new content. That solves the history issues.
I know this is a history problem but if you are still open to other possibilities, I think jquery-pjax is actually more suitable for what you are trying to do.
UPDATE I think this should work.
count.html
<div id="pjax-container">
<a id="pjax" data-pjax href="#">Next Page</a>
</div>
javascript
// get URL parameter (count): http://stackoverflow.com/questions/1403888/get-url-parameter-with-jquery
function getURLParameter(name) {
return decodeURI(
(RegExp(name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1]
);
}
$(document).on('pjax:beforeSend', function() {
// your fading code goes here
})
$(document).on('pjax:complete', function() {
// fade out
// and then modify the anchor's href with something like
var new_count = getURLParameter('count') + 1;
$('a#pjax').attr('href', 'count.html?count=?' + new_count);
})
// where the pjaxed content should go
$(document).pjax('a[data-pjax]', '#pjax-container')

Change page using a button in SP2010, strange behaviour

I'm trying to do something in Sharepoint 2010 that ought to be very simple, create a button that changes page (to a "create new item" form as it happens).
I set up a Content Editor Webpart and put a button in it (not in a form, because in Sharepoint the whole page is a form) with an "onclick" handler that changed the windows.location.href.
In 2010 the CEWP fights you a bit when you try to enter non-trivial HTML, it keeps escaping characters like "&" which can be a real pain. However in the end I got the right content entered.
It didn't work (the page just refreshed itself without changing URL). By checking on StackOverflow I found some recommendations for a more robust form for the CEWP content, which ended up as-
<script type="text/javascript">
function submit_rec(){
window.location.href = "<my server root URL>/Lists/Rec/NewForm.aspx";
return;
}
</script>
<button onclick="javascript:return submit_rec();return false"/>Submit a Recommendation</button>
Here's the strange part.
If I use Firebug and put a breakpoint in the submit_rec() function this works fine. But without a breakpoint, it goes back to the behaviour of always returning to the current page.
It seems there's a timing issue, or Sharepoint is taking control after my URL starts to load, and reloads the original page again!
Anyone seen this before and found a solution?
Ideas and suggestions woudl be much appreciated.
Regards: colin_e
Try this:
javascript:SP.UI.ModalDialog.OpenPopUpPage('/dev/KfD/KfDdev/Lists/Recommendation/New‌​Form.aspx');return false;
in the onclick event
Thanks to everyone who responded. With some more experimentation, and following hints from other threads on Stackoverflow, I was finally able to get this working.
My mistake with my last effort, using the Sharepoint builtin OpenNewFormUrl() function, was to expect this this would be a global function defined in a central library by SP. Turns out it's not, it has to be defined separately on every page where it's used, partly because it hard-codes the size of the popup frame for the library edit form.
(Yes this is ugly, like a lot of Sharepoint under the covers, anyway, I digress...)
I was able to get a Sharepoint 2010 style "popup" editor working with a button of the same style as the standard SP Document Centre "Submit a Document" button using the following code in a Content Editor WebPart. I have no idea what the script does in detail, I just copied it from the Document Centre site template home page-
<script type="text/javascript">
// <![CDATA[
function ULS18u(){var o=new Object;o.ULSTeamName="DLC Server";o.ULSFileName="default.aspx";return o;}
var navBarHelpOverrideKey = "wssmain";
// ]]>
function OpenNewFormUrl(url)
{ULS18u:;
var options = {width:640, height:720};
SP.UI.ModalDialog.commonModalDialogOpen(url, options, null, null);
}
</script>
<div class="ms-uploadbtnlink">
<button onclick="javascript:OpenNewFormUrl('/dev/KfD/KfDdev/Lists/Recommendation/NewForm.aspx');return false;" type="submit"><nobr><img alt="Submit a Recommendation" src="/_layouts/Images/uploaddoc.png"/> <span>Submit a Recommendation</span></nobr>
</button>
</div>
I'm wary of what setup this will do if (say) the users screen is smaller than the hard-coded popup size, and i'm still confused as to why my earlier (and much simpler) efforts failed, but at least I have a working soluion.

Detecting javascript during login of an asp.net MVC app...does this code look ok?

My LogIn action originally looked like this:
return new RedirectResult(nameValueCollection["ReturnUrl"]);
But, I would like to know whether the client has JavaScript enabled before the home page loads, so I changed it to this:
return View(new LogInViewModel { ReturnUrl = nameValueCollection["ReturnUrl"] });
And send the following view instead of the instant-redirect:
#model Obr.Web.Models.LogInViewModel
#{
Layout = null;
string noJSReturnUrl = Model.ReturnUrl + (Model.ReturnUrl.Contains("?") ? "&" : "?") + "noJS=true";
}
<!doctype html>
<html>
<head>
<title>Loggin in...</title>
<meta http-equiv="REFRESH" content="1;url=#noJSReturnUrl">
<script type="text/javascript">
window.location = "#Model.ReturnUrl";
</script>
</head>
<body>
<noscript>
Loggin in...<br />
Click here if you are not redirected promptly.
</noscript>
</body>
</html>
The idea is that if the user does not have JavaScript enabled, they see a brief loading message, and the home page loads after a second. If JavaScript is enabled, the page reloads instantly. In the future I could even post to the server the dimensions of the viewport and such.
Does this look like it would work? If the window.location command takes longer than a second to run, will it be interrupted by the meta refresh, or does it block that refresh? I am hoping the latter, so I don't need to increase the delay for those non-js people.
I figure my new way adds a little extra weight to the payload of the redirect, but it's not an extra round-trip or anything, is it? The redirect happens anyway, does it not?
Update: I neglected to mention a very important point. I do not actually have control over the login screen itself, only the page it posts to. This code is part of a product that relies on an external authentication mechanism.
You do not need the extra redirect just to detect javascript. On the original form where the user logs in, create a hidden form element javaScriptEnabled with a default value of false. Then use JavaScript to set the value to true. Then you can read this value in the handler. If it's true, then JS is enabled.
No extra page needed.
Since you can't change the original login form then your solution looks good. It won't display anything to the user who has JS and should look just like another redirect, with just an extra hop.
Once you write a new url to window.location then the browser will stop processing the current page's js and timers and everything and simply move on to retrieving/processing the next page.

Categories