diff options
Diffstat (limited to 'assets/js')
| -rw-r--r-- | assets/js/votes.js | 200 | 
1 files changed, 139 insertions, 61 deletions
| diff --git a/assets/js/votes.js b/assets/js/votes.js index 4fb585d..2fa9097 100644 --- a/assets/js/votes.js +++ b/assets/js/votes.js @@ -1,75 +1,153 @@  (function(document, $){      'use strict';      var jsonpRe = /^\/\*[\s\S]*?\*\/jsonp\(([\s\S]*)\)$/m; +    var ghLimits = {search: {}, core: {}}; +    var stopId = 0; +    var queue = {search: [], core: []}; +    var todo = 1; -    function requestAll(start) { -	$.ajax({ +    function requestLater(what, how, arg) { +	var when = rateTimeout(what); +	if (when >= 0) { +	    var empty = queue[what].length == 0; +	    queue[what].push([how, arg]); +	    if (empty) window.setTimeout(function(){reQueue(what);}, when); +	} else { +	    ghLimits[what].remaining--; +	    how(arg); +	} +    } + +    function reQueue(what) { +	limitsThen(what, function(q) { +	    q.forEach(function(e) { +		requestLater(what, e[0], e[1]); +	    }); +	}, queue[what].splice(0, queue[what].length)); +    } + +    function signalDone() { +	if (!todo) $("#th-votes").html("Votes"); +    } + +    function _jsonpToJson(dta, typ) { +	if (typ == "json") { +	    return dta.replace(jsonpRe, "$1"); +	} +	return dta; +    } + +    function jj(url) { +	return $.ajax({  	    accepts: { json: 'application/vnd.github.squirrel-girl-preview' },  	    dataType: 'json', -	    url: start, +	    url: url + (url.indexOf('callback=') === -1 +			? (url.indexOf('?') === -1 ? '?' : ';') + 'callback=jsonp' +			: ''),  	    jsonp: false,  	    jsonpCallback: 'jsonp', -	    dataFilter: function(dta, typ) { -		if (typ == "json") { -		    return dta.replace(jsonpRe, "$1"); -		} -		return dta; -	    } -	}) -	    .done(function(r) { -		var remaining = r.meta['X-RateLimit-Remaining']; -		var rateReset = r.meta['X-RateLimit-Reset']; -		var timeOut = 0; -		var hasMore = false; -		if (remaining < 10) { -		    timeOut = 1000 + rateReset * 1000 - (new Date() / 1); -		} -		if (timeOut < 0) timeOut = 0; -		if (r.meta.Link) { -		    r.meta.Link.forEach(function(l) { -			if (l[1].rel == "next") { -			    window.setTimeout(function(){requestAll(l[0]);}, timeOut); -			    hasMore = true; -			    return; -			} -		    }); -		} -		if (timeOut > 0) { -		    timeOut += 1000; +	    dataFilter: _jsonpToJson +	}); +    } + +    function searchVotes(url) { +	var start = url.indexOf("//") !== -1 ? url +		: 'https://api.github.com/search/issues?q=votes+in:title+state:closed+type:issue+' +		+ 'repo:' + url + ';sort=updated'; +	jj(start).done(function(r) { +	    var hasMore = fetchNext('search', r.meta, searchVotes); +	    if (hasMore) todo++; +	    r.data.items.forEach(function(e) { +		if (stopId && e.number > stopId) return; +		if (e.title != "votes") return; +		if (e.locked) { stopId = e.number; return; } +		todo++; +		requestLater('core', requestComments, e.comments_url); +		todo++; +		requestLater('core', requestComments, e.comments_url + '?page=2'); +		todo++; +		requestLater('core', requestComments, e.comments_url + '?page=3'); +		//todo++; +		//requestLater('core', requestComments, e.comments_url + '?page=4'); +	    }); +	    todo--; +	    signalDone(); +	}); +    } + +    function rateTimeout(what) { +	if ($.isEmptyObject(ghLimits[what])) return -1; + +	var remaining = ghLimits[what].remaining; +	var rateReset = ghLimits[what].reset; +	var limit = ghLimits[what].limit; + +	var timeOut = -1; +	if (remaining < Math.log(limit) + Math.sqrt(limit)) { +	    timeOut = 1000 + rateReset * 1000 - (new Date() / 1); +	    if (timeOut < -1) timeOut = 0; +	} +	return timeOut; +    } + +    function updateLimits(what, meta) { +	ghLimits[what].remaining = meta['X-RateLimit-Remaining']; +	ghLimits[what].reset = meta['X-RateLimit-Reset']; +    } + +    function fetchNext(what, meta, how) { +	var hasMore = false; +	updateLimits(what, meta); +	if (meta.Link) { +	    meta.Link.forEach(function(l) { +		if (l[1].rel == "next") { +		    hasMore = true; +		    requestLater(what, how, l[0]); +		    return;  		} +	    }); +	} +	return hasMore; +    } -		r.data.forEach(function(e) { -		    e.body = e.body.replace(/\r/g, ""); -		    var redir = e.body.match(/^#(\d+)$/); -		    if (redir) { -			var l = start.replace(/(\/issues\/)\d+(\/comments\?)/, "$1" + redir[1] + "$2").replace(/&.*/, ""); -			window.setTimeout(function(){requestAll(l);}, timeOut); -			hasMore = true; -			return; -		    } -			 -		    var lines = e.body.split("\n"); -		    var script = lines[0].replace(/[^-a-zA-Z0-9_]/g, "_"); -		    if (script == "comment") { -			script = "adv_windowlist_pl"; -		    } -		    var st = "#script-" + script + " .votes"; -		    var row = $(st); -		    if (row.length) { -			var votes = 1+ e.reactions['+1'] - e.reactions['-1']; -			var link = "*"; -			if (e.reactions['heart'] >= votes) { -			    link = "💜"; -			} -			row.html( "" + votes ); -			 -			row.append("<span><a data-toggle=\"tooltip\" title=\"vote on github\" href=\"" + e.html_url + "\">"+link+"</a></span>"); -		    } -		}); -		if (!hasMore) { -		    $("#th-votes").html("Votes"); +    function requestComments(start) { +	jj(start).done(function(r) { +	    updateLimits('core', r.meta); +	    if (r.meta.status == 403 && !r.meta['X-RateLimit-RateLimit']) { +		requestLater('core', requestComments, start); +		return; +	    } +	    //var hasMore = fetchNext('core', r.meta, requestComments); +	    //if (hasMore) todo++; +	    r.data.some(function(e) { +		e.body = e.body.replace(/\r/g, ""); +		var lines = e.body.split("\n"); +		var redir = e.body.match(/^#(\d+)$/); +		if (redir) return true; +		var script = lines[0].replace(/^## /, "").replace(/[^-a-zA-Z0-9_]/g, "_"); +		var row = $("#script-" + script + " .votes"); +		if (row.length) { +		    var votes = 1+ e.reactions['+1'] - e.reactions['-1']; +		    var link = "*"; +		    if (e.reactions['heart'] >= votes) link = "💜"; +		    row.html( "" + votes ); +		    row.append("<span><a data-toggle=\"tooltip\" title=\"vote on github\" href=\"" +			       + e.html_url + "\">"+link+"</a></span>");  		} +		return false;  	    }); +	    todo--; +	    signalDone(); +	});      } -    requestAll('https://api.github.com/repos/ailin-nemui/scripts.irssi.org/issues/2/comments?callback=jsonp'); + +    function limitsThen(what, how, arg) { +	jj('https://api.github.com/rate_limit').done(function(r) { +	    ghLimits = r.data.resources; +	    requestLater(what, how, arg); +	}); +    } + +    limitsThen('search', searchVotes, 'ailin-nemui/scripts.irssi.org'); +  })(document, $); | 
