javascript - GM_xmlhttpRequest data is being placed in the wrong places -
i using following excellent userscript (for chrome, chrome's tampermonkey , firefox greasemonkey). it's supposed display movie ratings next each imdb movie link, stopped working properly.
this complete script:
// ==userscript== // @name add imdb rating next imdb links (+voter count) // @author ali // @description adds movie ratings , number of voters imdb link. modified version of http://userscripts.org/scripts/show/9174 // @include * // @version 2013-05-12 // @namespace http://userscripts.org/scripts/show/96884 // @grant gm_xmlhttprequest // @downloadurl http://www.alibakir.com/upload/addimdbratings.js // @updateurl http://www.alibakir.com/upload/addimdbratings.js // ==/userscript== var imdbpluginlinks = document.links; var imdbcontinueelement=document.createelement("button"); imdbcontinueelement.innerhtml="get rating"; function processimdblinks(s){ imdbcontinueelement.style.display = 'none'; var r=0; (imdbi = s; imdbi < imdbpluginlinks.length; imdbi++) { if (imdbpluginlinks[imdbi].href.indexof("/title/") != -1 && imdbpluginlinks[imdbi].href.indexof("imdb.") != -1){ if(r>300){ imdbcontinueelement.onclick=function(){ processimdblinks(imdbi); }; imdbcontinueelement.style.display='inline'; imdbpluginlinks[imdbi].parentnode.insertbefore(imdbcontinueelement, imdbpluginlinks[imdbi]); break; } r++; gm_xmlhttprequest({ method: 'get', headers: { }, url: imdbpluginlinks[imdbi].href, onload: function (imdbi){return function(result) { rating = result.responsetext.match(/users rated (.*) \(/); votes = result.responsetext.match(/\((.*) votes\) -/); imdbpluginlinks[imdbi].parentnode.insertbefore(document.createelement("span"), imdbpluginlinks[imdbi]).innerhtml = (rating ? "<b> [" + rating[1] + " - "+votes[1]+"] </b>" : "<b style='color: red;'>[na] </b> "); }}(imdbi) }); } } } processimdblinks(0);
, how an example page looks @ moment:
can see, script displays results in wrong places.
why present them in wrong place , how can fixed?
the issue causing main complaint (results in wrong places) gm_xmlhttprequest
operates asynchronously (which good) , onload
improperly constructed.
you either need wrap call gm_xmlhttprequest
in proper closure or provide context
in gm_xmlhttprequest
call. (see code below.)
for more information on why closures needed, see this answer same type of problem.
other big problems include ajax-fetching dozens of improper links , firing on every page , iframe. both of these slow browser down quite bit.
don't use @include *
. if don't mind, other users of script will. add @include
or @match
lines sites know have imdb links.
i thought might want use script myself, started cleaning up. can read inline comments , compare original script idea of of lesser problems. (don't use onclick
, check match
returns, etc.)
// ==userscript== // @name add imdb rating next imdb links (+voter count) // @description adds movie ratings , number of voters imdb link. modified version of http://userscripts.org/scripts/show/96884 // @match *://www.imdb.com/* // @grant gm_xmlhttprequest // ==/userscript== var maxlinksatatime = 50; //-- pages can have 100's of links fetch. don't spam server or browser. var fetchedlinkcnt = 0; function processimdb_links () { //--- links imbd movie/tv pages. var linkstoimbd_shows = document.queryselectorall ("a[href*='/title/']"); (var j = 0, l = linkstoimbd_shows.length; j < l; j++) { var currentlink = linkstoimbd_shows[j]; /*--- strict tests correct imdb link keep spamming page erroneous results. */ if ( ! /^(?:www\.)?imdb\.com$/i.test (currentlink.hostname) || ! /^\/title\/tt\d+\/?$/i.test (currentlink.pathname) ) continue; if (! currentlink.getattribute ("data-gm-fetched") ){ if (fetchedlinkcnt >= maxlinksatatime){ //--- position "continue" button. continuebttn.style.display = 'inline'; currentlink.parentnode.insertbefore (continuebttn, currentlink); break; } fetchtargetlink (currentlink); //-- ajax-in ratings given link. //---mark link data attribute, know it's been fetched. currentlink.setattribute ("data-gm-fetched", "true"); fetchedlinkcnt++; } } } function fetchtargetlink (linknode) { //--- function provides closure callbacks can work correctly. /*--- must either call ajax in closure or pass context. tampermonkey not implement context correctly! (tries json serialize dom node.) */ gm_xmlhttprequest ( { method: 'get', url: linknode.href, //context: linknode, onload: function (response) { prependimdb_rating (response, linknode); }, onload: function (response) { prependimdb_rating (response, linknode); }, onabort: function (response) { prependimdb_rating (response, linknode); } } ); } function prependimdb_rating (resp, targetlink) { var iserror = true; var ratingtxt = "** unknown error!"; if (resp.status != 200 && resp.status != 304) { ratingtxt = '** ' + resp.status + ' error!'; } else { if (/\(awaiting \d+ votes\)|\(voting begins after release\)|in development/i.test (resp.responsetext) ) { ratingtxt = "nr"; iserror = false; } else { var ratingm = resp.responsetext.match (/users rated (.*) \(/); var votesm = resp.responsetext.match (/\((.*) votes\) -/); if (ratingm && ratingm.length > 1 && votesm && votesm.length > 1) { iserror = false; ratingtxt = ratingm[1] + " - " + votesm[1]; } } } var resltspan = document.createelement ("span"); resltspan.innerhtml = '<b> [' + ratingtxt + '] </b> '; if (iserror) resltspan.style.color = 'red'; //var targetlink = resp.context; //console.log ("targetlink: ", targetlink); targetlink.parentnode.insertbefore (resltspan, targetlink); } //--- create continue button var continuebttn = document.createelement ("button"); continuebttn.innerhtml = "get ratings"; continuebttn.addeventlistener ("click", function (){ fetchedlinkcnt = 0; continuebttn.style.display = 'none'; processimdb_links (); }, false ); processimdb_links ();
Comments
Post a Comment