jQuery ajax function not working in Safari (Firefox, Chrome, IE okay) - javascript

I'm no javascript wiz, but am a bit puzzled as to how this is working in three major browsers, but not Safari... is there something wrong with this code? Basically I'm just using this in conjunction with a php/mysql callback at the given url to track link clicks.
Drupal.behaviors.NodeDownloadCounter = function() {
$('a.ndc-link').click(function() {
$.post('http://www.pixeledmemories.com/node-download-counter/log/' + this.name);
return true;
});
};
Using Drupal behaviors here instead of
$(document).ready(function() {
(correct Drupal method) but I've tried it both ways and it doesn't make a difference.
I've also tried removing "return true", but with no effect.
Okay, further testing reveals that having the click trigger an alert DOES work in Safari:
$('a.ndc-link').click(function() {
alert('testing (ignore)');
$.post('http://www.pixeledmemories.com/node-download-counter/log/' + this.name);
return true;
});
But still nothing being logged to mysql. Here is my callback function:
function node_download_counter_log($nid)
{
global $user;
$timestamp = time();
$title = db_result(db_query("SELECT title FROM {node} WHERE nid = %d", $nid));
db_query("INSERT INTO {node_download_counter} (nid, title, download_count, last_download, last_uid) VALUES (%d, '%s', %d, %d, %d)
ON DUPLICATE KEY UPDATE download_count=download_count+1, last_download = %d, last_uid = %d", $nid, $title, 1, $timestamp, $user->uid, $timestamp, $user->uid);
db_query("INSERT INTO {node_download_counter_log} (nid, title, uid, timestamp) VALUES (%d, '%s', %d, %d)", $nid, $title, $user->uid, $timestamp);
}

Sounds like the problem is the browser is changing the page before the data post can be finished. You can try adding return false to see if it starts working then. If it does, you are going to need to add a short delay before following the link.
UPDATE:
Since it works try adding the following before "return true;"
if(jQuery.browser.safari){
setTimeout("window.location.href= '"+this.href+"'",500);
return false;
}

Okay, based on our conversation on comments above, try
$('a.ndc-link').click(function() {
var href = this.href;
$.post('http://www.pixeledmemories.com/node-download-counter/log/' + this.name,
function() {
window.location.href = href;
}
);
return false;
});

Firs,t you have to be careful not to attach your handler more than once to each 'a.ndc-link', one way to do it is to tag the elements with a custom class.
Drupal.behaviors.NodeDownloadCounter = function() {
$('a.ndc-link:not(.node-download-counter-processed)').addClass('node-download-counter-processed').click(function(event) {
// ...
});
};
One reason I see for this not to work is that, because it closes the page to open the link target, Safari will cancel the $.post request before it is actually sent to the server. Returning false and calling event.preventDefault (event being the first argument of your event handler) should prevent this from happening but will also prevent the browser to actually load the link's target. One way to solve this is to defer the page change until the POST request is complete.
Drupal.behaviors.NodeDownloadCounter = function() {
$('a.ndc-link:not(.node-download-counter-processed)').addClass('node-download-counter-processed').click(function(event) {
var link = this;
event.preventDefault();
$.post('http://www.pixeledmemories.com/node-download-counter/log/' + this.name, function() {
window.location.href = link.href;
});
return false;
});
};
But this will only works if there is no error in the POST request.
A better solution would be to hijack the server-side handler for the link target to add the click logging and then call the original handler.

Related

ajaxComplete with getJSON causing loop

I am using ajaxComplete to run some functions after dynamic content is loaded to the DOM. I have two separate functions inside ajaxComplete which uses getJSON.
Running any of the functions once works fine
Running any of them a second time causes a loop cause they are using getJSON.
How do I get around this?
I'm attaching a small part of the code. If the user has voted, clicking the comments button will cause the comments box to open and close immediately.
$(document).ajaxComplete(function() {
// Lets user votes on a match
$('.btn-vote').click(function() {
......
$.getJSON(path + 'includes/ajax/update_votes.php', { id: gameID, vote: btnID }, function(data) {
......
});
});
// Connects a match with a disqus thread
$('.btn-comment').click(function() {
var parent = $(this).parents('.main-table-drop'), comments = parent.next(".main-table-comment");
if (comments.is(':hidden')) {
comments.fadeIn();
} else {
comments.fadeOut();
}
});
});
Solved the problem by checking the DOM loading ajax request URL
$(document).ajaxComplete(event,xhr,settings) {
var url = settings.url, checkAjax = 'list_matches';
if (url.indexOf(checkAjax) >= 0) { ... }
}

Handling State changes jQuery and History.js

Ok, so I need some insight into working with History.js and jQuery.
I have it set up and working (just not quite as you'd expect).
What I have is as follows:
$(function() {
var History = window.History;
if ( !History.enabled ) {
return false;
}
// Capture all the links to push their url to the history stack and trigger the StateChange Event
$('.ajax-link').click(function(e) {
e.preventDefault();
var url = this.href; //Tells us which page to load
var id = $(this).data('passid'); //Pass ID -- the ID in which to save in our state object
e.preventDefault();
console.log('url: '+url+' id:'+id);
History.pushState({ 'passid' : id }, $(this).text(), url);
});
History.Adapter.bind(window, 'statechange', function() {
console.log('state changed');
var State = History.getState(),
id = State.data.editid; //the ID passed, if available
$.get(State.url,
{ id: State.data.passid },
function(response) {
$('#subContent').fadeOut(200, function(){
var newContent = $(response).find('#subContent').html();
$('#subContent').html(newContent);
var scripts = $('script');
scripts.each(function(i) {
jQuery.globalEval($(this).text());
});
$('#subContent').fadeIn(200);
});
});
});
}); //end dom ready
It works as you'd expect as far as changing the url, passing the ID, changing the content. My question is this:
If I press back/forward on my browser a couple times the subContent section will basically fadeIn/fadeOut multiple times.
Any insight is appreciated. Thanks
===================================================
Edit: The problem was in my calling all of my <script> and Eval them on each statechange. By adding a class="no-reload" to the history controlling script tag I was able to do:
var scripts = $('script').not('.no-reload');
This got rid of the problem and it now works as intended. Figure I will leave this here in case anyone else runs into the same issue as I did.
The problem was in my calling of all of my <script> and Eval them on each statechange. By adding a class="no-reload" to the history controlling script tag I was able to do:
var scripts = $('script').not('.no-reload');
This got rid of the problem and it now works as intended. Figure I will leave this here in case anyone else runs into the same issue as I did.

automatic clicks on links and doing something with every page's DOM

i have some links in a web page ,what i want to do :
Trigger click event on every link
When the page of every link is loaded , do something with page's DOM(fillProducts here)
What i have tried :
function start(){
$('.category a').each(function(i){
$.when($(this).trigger('click')).done(function() {
fillProducts() ;
});
})
}
Thanks
What you want to do is much more complicated than you seem to be giving it credit for. If you could scrape webpages, including AJAX content, in 7 lines of js in the console of a web browser you'd put Google out of business.
I'm guessing at what you want a bit, but I think you want to look at using a headless browser, e.g. PhantomJs. You'll then be able to scrape the target pages and write the results to a JSON file (other formats exist) and use that to fillProducts - whatever that does.
Also, are you stealing data from someone else's website? Cause that isn't cool.
Here's a solution that may work for you if they are sending their ajax requests using jQuery. If they aren't you're going to need to get devilishly hacky to accomplish what you're asking (eg overriding the XMLHttpRequest object and creating a global observer queue for ajax requests). As you haven't specified how they're sending the ajax request I hope this approach works for you.
$.ajaxSetup({
complete: function(jQXHR) {
if(interested)
//do your work
}
});
The code below will click a link, wait for the ajax request to be sent and be completed, run you fillProducts function and then click the next link. Adapting it to run all the clicks wouldn't be difficult
function start(){
var links = $('.category a');
var i = 0;
var done = function() {
$.ajaxSetup({
complete: $.noop//remove your handler
});
}
var clickNext = function() {
$(links.get(i++)).click();//click current link then increment i
}
$.ajaxSetup({
complete: function(jQXHR) {
if(i < links.length) {
fillProducts();
clickNext();
} else {
done();
}
}
});
clickNext();
}
If this doesn't work for you try hooking into the other jqXHR events before hacking up the site too much.
Edit here's a more reliable method in case they override the complete setting
(function() {
var $ajax = $.ajax;
var $observer = $({});
//observer pattern from addyosmani.com/resources/essentialjsdesignpatterns/book/#observerpatternjquery
var obs = window.ajaxObserver = {
subscribe: function() {
$observer.on.apply($observer, arguments);
},
unsubscribe: function() {
$observer.off.apply($observer, arguments);
},
once: function() {
$observer.one.apply($observer, arguments);
},
publish: function() {
$observer.trigger.apply($observer, arguments);
}
};
$.ajax = function() {
var $promise = $ajax.apply(null, arguments);
obs.publish("start", $promise);
return $promise;
};
})();
Now you can hook into $.ajax calls via
ajaxObserver.on("start", function($xhr) {//whenever a $.ajax call is started
$xhr.done(function(data) {
//do stuff
})
});
So you can adapt the other snippet like
function start(){
var links = $('.category a');
var i = 0;
var clickNextLink = function() {
ajaxObserver.one("start", function($xhr) {
$xhr.done(function(data) {
if(i < links.length) {
fillProducts();
clickNextLink();
} else {
done();
}
});
})
$(links.get(i++)).click();//click current link then increment i
}
clickNextLink();
}
try this:
function start(){
$('.category a').each(function(i){
$(this).click();
fillProducts() ;
})
}
I get ya now. This is like say:
when facebook loads, I want to remove the adverts by targeting specific class, and then alter the view that i actually see.
https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/
Is a plugin for firefox, this will allow you to create a javascript file, will then allow you to target a specific element or elements within the html rendered content.
IN order to catch the ajax request traffic, you just need to catcher that within your console.
I can not give you a tutorial on greasemonkey, but you can get the greasemonkey script for facebook, and use that as a guide.
http://mashable.com/2008/12/25/facebook-greasemonkey-scripts/
hope this is it

Loading GIF while AJAX completes

This should be quite simple but I'll be darned if I can work it out. Just trying to get a div to display while my ajax is processing and then hide once done (I've put a sleep in there purely to test its working as locally it loads so fast I'm not sure if its working or not)!
The html page has this code in the script: -
$(document).ready(function(){
$("#loadingGIF").ajaxStart(function () {
$(this).show();
});
$("#loadingGIF").ajaxStop(function () {
window.setTimeout(partB,5000)
$(this).hide();
});
function partB(){
//just because
}
var scenarioID = ${testScenarioInstance.id}
var myData = ${results as JSON}
populateFormData(myData, scenarioID);
});
There is then a div in my page like so (which I can see in the source of the page just hidden): -
<div id="loadingGIF" ><img src='${application.contextPath}/images/spinner.gif' height="50" width="50"></div>
The ready code then goes off and calls this: -
function populateFormData(results, scenarioID) {
$table = $('#formList')
for(var i in results){
var formIDX = (results[i]["forms_idx"])
var formID = (results[i]["form_id"])
appendSubTable(formIDX, scenarioID, $table, formID);
}
}
Which references this multiple times calling several AJAX posts: -
function appendSubTable(formIDX, scenarioID, $table, formID) {
var $subTable = $table.find("#" + formIDX).find('td:eq(1)').find("div").find("table")
var url = "**Trust me this bits OK ;) **"
$.post(url, {
formIDX : formIDX, scenarioID : scenarioID, formID :formID
}, function(data) {
$subTable.append(data)
}).fail(function() {
});
}
Any pointers gratefully received...
Interestingly I bunged some alerts into my ajaxstart and stop and neither show up ever so I'm missing something obvious :S When I check the console in firefox I can see that all my POSTs are completing....
You should probably add the Ajaxstart and stop global event handlers to the document node like this
$(document).ajaxStart(function () {
$("#loadingGIF").show();
});
I realized my problem, I needed to register the ajaxstart and stop to the document not the div!
So instead of this: -
$("#loadingGIF").ajaxStart(function () {
$(this).show();
});
I now have: -
$(document).ajaxStart(function () {
$("#loadingGIF").show();
});
I assume this is because its the document that the ajax is running against not the div although my understanding there may not be 100% accurate at least this works so please tell me if I've misunderstood this! :)
#jbl, thanks for this pointer I did this to also leave the notification on screen for a few more moments just to make sure everything is loaded.

javascript code making url link undefined

I am working on this javascript code and when is goes in the head and I refresh it goes to a 404 page.
Please can someone help.
<script type="text/javascript">
function recordOutboundLink(link, category, action) {
try {
var myTracker = _gat._getTrackerByName();
_gaq.push(['myTracker._trackEvent', category, action]);
setTimeout('document.location = "' + link.href + '"', 100)
} catch (err) { }
}
$(document).ready(function () { $('#myid').click(recordOutboundLink(this, 'regular xxxxx', 'xxxx.example.com')); });
</script>
You're trying to register the result of recordOutboundLink() as a click handler, causing the function to run first, evaluating window.href as the page to redirect to. The value of window.href is typically undefined, so the browser will try to redirect to http://undefined or something similar.
Instead, you should only execute the function when something is clicked, like so:
$(document).ready(function () {
$('#myid').click(function() {
recordOutboundLink(this, 'regular xxxxx', 'http://xxxx.example.com');
return false;
});
I believe the Google docs mention something like this:
tada click me
Edit
Your locations should always be absolute, i.e. start with http://, https:// or simply //.
You need to pass the complete url to the method, ie, with the http:// part
so either use:
.click(recordOutboundLink(this, 'regular xxxxx', 'http://xxxx.example.com'))
or
.click(recordOutboundLink(this, 'regular xxxxx', '//xxxx.example.com'))

Categories

Resources