jQuery ajax function not working in Safari (Firefo

2019-06-03 05:48发布

问题:

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);

}

回答1:

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;
}


回答2:

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;
});


回答3:

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.