// ==UserScript==
// @name GitHub Show Repo Issues
// @namespace github-show-repo-issues
// @description Show repo issues count on the repository tab & organization page (https://github.com/:user)
// @version 2.2.0
// @include https://github.com/*
// @grant GM_addStyle
// @grant GM_xmlhttpRequest
// @run-at document-idle
// @author Rob Garrison >> http://github.com/Mottie
// @downloadURL none
// ==/UserScript==
/* global GM_addStyle, GM_xmlhttpRequest */
( function() {
'use strict';
var busy = false,
addIssues = function() {
// look for repo tab or user/organization page
if ( document.querySelectorAll( '.tabnav-tab.selected, .repo-list' ).length &&
// and not already applied
!document.querySelectorAll( '.repo-list-stat-item.issues' ).length ) {
// set busy flag to ignore mutation observer firing while adding new content
busy = true;
// Does not include forks & only includes the first 10 repos, or first 20 on the
// organization page - these are the repos showing the participation graphs
var user, len, url,
items = document.querySelectorAll( '.repo-list-item' ),
// bug icon
icon = '',
// issue count = get all repos from user => api v3 - https://api.github.com/users/:user/repos,
// then look for "open_issues_count" in the named repos
// previsouly used https://api.github.com/repos/:user/:repo/issues?state=open (first 30 issues only)
api = 'https://api.github.com/users';
items = Array.prototype.filter.call( items, function( item ) {
var cl = item.classList;
return cl.contains( 'public' ) && !cl.contains( 'fork' );
});
len = items.length;
// expecting fork link to look like this:
//
// 1
//
url = len ? items[ 0 ].querySelector( 'a.repo-list-stat-item[aria-label="Forks"]' ).getAttribute( 'href' ) : '';
user = ( url || '' ).match( /^\/[^/]+/ );
if ( user && user.length ) {
// add bug image background
GM_addStyle([
'.repo-list-stats a.issues svg { position: relative; top: 2px; fill: #888; }',
'.repo-list-stats a.issues:hover svg { fill: #4078C0; }'
].join(''));
GM_xmlhttpRequest({
method : 'GET',
url : api + user[ 0 ] + '/repos',
onload : function( response ) {
var itemIndex, repoIndex, repoLen, repo, link,
data = JSON.parse( response.responseText || 'null' );
if ( data ) {
repoLen = data.length;
for ( itemIndex = 0; itemIndex < len; itemIndex++ ) {
link = items[ itemIndex ].querySelector( 'a.repo-list-stat-item[aria-label="Forks"]' );
repo = ( link.getAttribute( 'href' ) || '' ).replace( '/network', '' ).slice( 1 );
for ( repoIndex = 0; repoIndex < repoLen; repoIndex++ ) {
if ( repo === data[ repoIndex ].full_name ) {
link.insertAdjacentHTML( 'afterend',
'' + icon + ' ' + data[ repoIndex ].open_issues_count + ''
);
}
}
}
}
busy = false;
}
});
} else {
busy = false;
}
} else {
busy = false;
}
},
containers = '#js-repo-pjax-container, #js-pjax-container, .js-contribution-activity',
targets = document.querySelectorAll( containers );
Array.prototype.forEach.call(targets, function(target) {
new MutationObserver( function( mutations ) {
mutations.forEach( function( mutation ) {
// preform checks before addIssues to minimize function calls
if ( !( busy || document.querySelectorAll( '.repo-list-stat-item.issues' ).length ) &&
document.querySelectorAll( '.tabnav-tab.selected, .repo-list' ).length &&
mutation.target === target ) {
addIssues();
}
});
}).observe( target, {
childList: true,
subtree: true
});
});
addIssues();
})();