github-contribution-ratio (typescript)

查看Github项目的贡献比例

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name              github-contribution-ratio (typescript)
// @author            Axetroy
// @collaborator      Axetroy
// @description       查看Github项目的贡献比例
// @version           0.1.0
// @update            2017-04-06 21:28:02
// @grant             GM_xmlhttpRequest
// @include           https://github.com*
// @connect           *
// @compatible        chrome  完美运行
// @compatible        firefox  完美运行
// @supportURL        http://www.burningall.com
// @run-at            document-idle
// @contributionURL   [email protected]|alipay.com
// @namespace         https://greasyfork.org/zh-CN/users/3400-axetroy
// @license           The MIT License (MIT); http://opensource.org/licenses/MIT
// ==/UserScript==

// Github源码:https://github.com/axetroy/github-contribution-ratio


/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;
/******/
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// identity function for calling harmony imports with the correct context
/******/ 	__webpack_require__.i = function(value) { return value; };
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, {
/******/ 				configurable: false,
/******/ 				enumerable: true,
/******/ 				get: getter
/******/ 			});
/******/ 		}
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 2);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var extend = __webpack_require__(1);
var Http = (function () {
    function Http(options) {
        this.options = options;
    }
    Http.prototype.request = function (method, url, body, headers) {
        if (headers === void 0) { headers = { 'Cookie': document.cookie }; }
        var options = extend({}, this.options, { method: method, url: url, data: body, headers: headers });
        if (options.url.indexOf('http') !== 0) {
            options.url = (options.base || '') + url;
        }
        options.url += '?client_id=b8257841dd7ca5eef2aa&client_secret=4da33dd6fcb0a01d395945ad18613ecf9c12079e';
        return new Promise(function (resolve, reject) {
            options.synchronous = true; // async
            options.onreadystatechange = function (response) {
                if (response.readyState !== 4)
                    return;
                response.status >= 200 && response.status < 400 ? resolve(response) : reject(response);
            };
            options.onerror = function (response) {
                console.error('http error');
                reject(response);
            };
            options.onabort = function (response) {
                console.error('http abort');
                reject(response);
            };
            options.ontimeout = function (response) {
                console.error('http timeout');
                reject(response);
            };
            GM_xmlhttpRequest(extend({}, options));
        });
    };
    Http.prototype.get = function (url, body, headers) {
        if (body === void 0) { body = null; }
        if (headers === void 0) { headers = {}; }
        return this.request('GET', url, body, headers);
    };
    Http.prototype.post = function (url, body, headers) {
        if (body === void 0) { body = null; }
        if (headers === void 0) { headers = {}; }
        return this.request('POST', url, body, headers);
    };
    return Http;
}());
var timeout = 5000;
exports.timeout = timeout;
var http = new Http({ timeout: timeout, base: 'https://api.github.com' });
exports.http = http;


/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var hasOwn = Object.prototype.hasOwnProperty;
var toStr = Object.prototype.toString;

var isArray = function isArray(arr) {
	if (typeof Array.isArray === 'function') {
		return Array.isArray(arr);
	}

	return toStr.call(arr) === '[object Array]';
};

var isPlainObject = function isPlainObject(obj) {
	if (!obj || toStr.call(obj) !== '[object Object]') {
		return false;
	}

	var hasOwnConstructor = hasOwn.call(obj, 'constructor');
	var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
	// Not own constructor property must be Object
	if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
		return false;
	}

	// Own properties are enumerated firstly, so to speed up,
	// if last one is own, then all properties are own.
	var key;
	for (key in obj) {/**/}

	return typeof key === 'undefined' || hasOwn.call(obj, key);
};

module.exports = function extend() {
	var options, name, src, copy, copyIsArray, clone,
		target = arguments[0],
		i = 1,
		length = arguments.length,
		deep = false;

	// Handle a deep copy situation
	if (typeof target === 'boolean') {
		deep = target;
		target = arguments[1] || {};
		// skip the boolean and the target
		i = 2;
	} else if ((typeof target !== 'object' && typeof target !== 'function') || target == null) {
		target = {};
	}

	for (; i < length; ++i) {
		options = arguments[i];
		// Only deal with non-null/undefined values
		if (options != null) {
			// Extend the base object
			for (name in options) {
				src = target[name];
				copy = options[name];

				// Prevent never-ending loop
				if (target !== copy) {
					// Recurse if we're merging plain objects or arrays
					if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) {
						if (copyIsArray) {
							copyIsArray = false;
							clone = src && isArray(src) ? src : [];
						} else {
							clone = src && isPlainObject(src) ? src : {};
						}

						// Never move original objects, clone them
						target[name] = extend(deep, clone, copy);

					// Don't bring in undefined values
					} else if (typeof copy !== 'undefined') {
						target[name] = copy;
					}
				}
			}
		}
	}

	// Return the modified object
	return target;
};



/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t;
    return { next: verb(0), "throw": verb(1), "return": verb(2) };
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [0, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
Object.defineProperty(exports, "__esModule", { value: true });
var http_1 = __webpack_require__(0);
function getUserName() {
    var matcher = location.href.match(/https:\/\/github\.com\/(\w+)\??/);
    return matcher[1];
}
function shouldRun() {
    return /https:\/\/github\.com\/\w+\?/.test(location.href) && location.search.indexOf('tab=repositories') >= 0;
}
function getRepositories() {
    return [].slice.call(document.querySelectorAll('.js-repo-list>li'))
        .filter(function (li) { return !li.getAttribute('contribute-ratio'); })
        .map(function (li) {
        var a = li.querySelector('h3>a');
        var match = a.pathname.match(/([^\/]+)\/([^\/]+)/);
        li.setAttribute('repository-owner', match[1]);
        li.setAttribute('repository-name', match[2]);
        return li;
    });
}
function main() {
    return __awaiter(this, void 0, void 0, function () {
        var userName, lis;
        return __generator(this, function (_a) {
            if (!shouldRun())
                return [2 /*return*/];
            userName = getUserName();
            console.info("Stating " + userName + "'s contribution...");
            lis = getRepositories();
            if (!lis.length)
                return [2 /*return*/];
            clearInterval(timer);
            timer = void 0;
            lis.forEach(function (li) {
                var owner = li.getAttribute('repository-owner');
                var name = li.getAttribute('repository-name');
                http_1.http.get("/repos/" + owner + "/" + name + "/stats/contributors")
                    .then(function (res) {
                    var raw = res.response;
                    if (!raw)
                        return;
                    var response = JSON.parse(raw);
                    response = Object.keys(response).length === 0 ? [] : response;
                    var contributes = response.filter(function (v) { return v["author"]["login"] === userName; }).map(function (v) { return v; });
                    var totalAdditions = 0;
                    var totalDeletions = 0;
                    var additions = 0;
                    var deletions = 0;
                    contributes.forEach(function (contribute) {
                        contribute.weeks.forEach(function (week) { return (additions += week.a) && (deletions += week.d); });
                    });
                    response.forEach(function (contribute) {
                        contribute.weeks.forEach(function (week) { return (totalAdditions += week.a) && (totalDeletions += week.d); });
                    });
                    var contributeRatio = (((additions + deletions) / (totalAdditions + totalDeletions)) * 100) + '';
                    li.setAttribute('total-additions', totalAdditions);
                    li.setAttribute('total-deletions', totalDeletions);
                    li.setAttribute('additions', additions);
                    li.setAttribute('deletions', deletions);
                    li.setAttribute('contribute-ratio', parseInt(contributeRatio));
                    var percent = parseInt(contributeRatio) > 0 ? parseInt(contributeRatio) : 1;
                    var uncontribution = document.createElement('span');
                    var contribution = document.createElement('span');
                    var container = document.createElement('span');
                    container.setAttribute('aria-label', "Contribution " + percent + "%");
                    var width = 155;
                    container.classList.add('d-inline-block');
                    container.classList.add('tooltipped');
                    container.classList.add('tooltipped-s');
                    container.style.width = '155px';
                    var contributionWidth = width * percent / 100;
                    contribution.style.width = contributionWidth + 'px';
                    contribution.style.borderBottom = '2px solid #009688';
                    contribution.style.display = 'inline-block';
                    uncontribution.style.width = width - contributionWidth + 'px';
                    uncontribution.style.borderBottom = '2px solid #9E9E9E';
                    uncontribution.style.display = 'inline-block';
                    container.appendChild(contribution);
                    container.appendChild(uncontribution);
                    li.querySelector('.col-3.float-right.text-right').appendChild(container);
                })
                    .catch(function (err) {
                    console.error(err);
                });
            });
            return [2 /*return*/];
        });
    });
}
(function (history) {
    var pushState = history.pushState;
    history.pushState = function (state) {
        if (typeof history["onpushstate"] == "function") {
            history["onpushstate"]({ state: state });
        }
        setTimeout(function () {
            run();
        });
        return pushState.apply(history, arguments);
    };
})(window.history);
var timer;
function run() {
    if (!shouldRun())
        return;
    timer = setInterval(function () {
        main();
    }, 1500);
}
run();


/***/ })
/******/ ]);