From 106d8db8379f79ca36ffaa294be2f97d76140c2c Mon Sep 17 00:00:00 2001 From: Giacomo Ferretti Date: Mon, 1 Aug 2022 14:02:36 +0200 Subject: [PATCH] bump v1.2.0 --- LICENSE | 2 +- README.md | 24 +++- js/inject.js | 19 ++-- js/main.js | 299 ++++++++++++++++++++++++-------------------------- manifest.json | 51 +++++---- pack.sh | 2 +- 6 files changed, 202 insertions(+), 195 deletions(-) diff --git a/LICENSE b/LICENSE index e90216b..633331b 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2020-2021 Giacomo Ferretti + Copyright 2020-2022 Giacomo Ferretti Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 2b299b6..1b1bbbe 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,27 @@ # Forks Diff Counter for GitHub -## Download +## Installation -Get the extension on the [chrome web store](https://chrome.google.com/webstore/detail/eencojgimolmahmdfpnfbcldppmlokfg). +### Chrome Web Store + +Get the extension on the [Chrome Web Store](https://chrome.google.com/webstore/detail/eencojgimolmahmdfpnfbcldppmlokfg). + +### Firefox Browser Add-ons + +Get the extension on the [Firefox Browser Add-ons](https://addons.mozilla.org/en-US/firefox/addon/forks-diff-counter-for-github/). + +### Unpacked + +#### Google Chrome + +1. Download the repo by using `git clone https://github.com/giacomoferretti/forks-diff-chrome` +2. Visit `chrome://extensions/` in Google Chrome +3. Enable "Developer mode" +4. Click on "Load unpacked" +5. Select the cloned folder + +When updating the plugin, remember to reload it. ## How to pack -Use the `pack.sh` script to generate the zip file. \ No newline at end of file +Use the `pack.sh` script to generate the zip file. diff --git a/js/inject.js b/js/inject.js index 0caaaf4..f67d675 100644 --- a/js/inject.js +++ b/js/inject.js @@ -1,14 +1,19 @@ /** - * Because we are running in an "isolated world" and need to hook 'replaceState', + * Because we are running in an "isolated world" and need to hook 'replaceState', * we need to inject our script into the page. * * https://developer.chrome.com/docs/extensions/mv3/content_scripts/#isolated_world */ (function () { - var s = document.createElement('script'); - s.src = chrome.runtime.getURL('js/main.js'); - s.onload = function() { - this.remove(); - }; - (document.head || document.documentElement).appendChild(s); + // ...chrome pls... + if (typeof browser === "undefined") { + var browser = chrome; + } + + const s = document.createElement("script"); + s.src = browser.runtime.getURL("js/main.js"); + s.onload = function () { + this.remove(); + }; + (document.head || document.documentElement).appendChild(s); })(); diff --git a/js/main.js b/js/main.js index 2a8a96c..41678a2 100644 --- a/js/main.js +++ b/js/main.js @@ -1,167 +1,152 @@ -'use strict'; - -const forksDiff = (function() { - // Icons - const starIcon = ''; - const forkIcon = ''; - const loadingIcon = ''; - - // Regex - const isEvenRegex = /
[\s]+This branch is even/; - const commitsAheadRegex = /
[\s]+This branch is ([0-9]*) commits? ahead/; - const commitsBehindRegex = /
[\s]+This branch is ([0-9]*) commits? behind/; - const commitsFullRegex = /
[\s]+This branch is ([0-9]*) commits? ahead, ([0-9]*) commit/; - const starsRegex = /([0-9]+) users? starred this repository/; - const githubUrlRegex = /https?:\/\/github\.com\/.*\/network\/members/; - - function appendSpace(e) { - e.appendChild(document.createTextNode(' ')); - } - - function processRepo(repoElement) { - // Add spinner - const spinner = document.createElement('span'); - spinner.innerHTML = loadingIcon; - repoElement.appendChild(spinner); - - // Extract repo URL - const repoUrl = repoElement.getElementsByTagName('a')[2].href; - - // Prepare request - const request = new XMLHttpRequest(); - request.addEventListener('load', function() { - repoElement.removeChild(spinner); - - const body = this.responseText; - - let commitsAhead = 0; - let commitsBehind = 0; - - // Check if repo is even - if (isEvenRegex.test(body)) { - const evenSpan = document.createElement('span'); - evenSpan.className = 'text-gray'; - evenSpan.appendChild(document.createTextNode('is even')); - repoElement.appendChild(evenSpan); - } else { - // Extract ahead and behind - let commitHistoryData = body.match(commitsFullRegex); - if (commitHistoryData != null) { - commitsAhead = parseInt(commitHistoryData[1]); - commitsBehind = parseInt(commitHistoryData[2]); - } else { - // Extract ahead - commitHistoryData = body.match(commitsAheadRegex); - if (commitHistoryData != null) { - commitsAhead = parseInt(commitHistoryData[1]); - } - - // Extract behind - commitHistoryData = body.match(commitsBehindRegex); - if (commitHistoryData != null) { - commitsBehind = parseInt(commitHistoryData[1]); - } - } - - // Add ahead commits - if (commitsAhead != 0) { - appendSpace(repoElement); - const commitsAheadText = document.createElement('span'); - commitsAheadText.className = 'cadd'; - commitsAheadText.appendChild(document.createTextNode('+' + commitsAhead)); - repoElement.appendChild(commitsAheadText); - } - - // Add behind commits - if (commitsBehind != 0) { - appendSpace(repoElement); - const commitsBehindCounter = document.createElement('span'); - commitsBehindCounter.className = 'cdel'; - commitsBehindCounter.appendChild(document.createTextNode('-' + commitsBehind)); - repoElement.appendChild(commitsBehindCounter); - } - } - - // Read stars - appendSpace(repoElement); - const stars = body.match(starsRegex); - const starIndicator = document.createElement('span'); - starIndicator.innerHTML = starIcon + ' ' + stars[1]; - repoElement.appendChild(starIndicator); - }); - - // Send request - request.open('GET', repoUrl); - request.send(); - } - - function mainButtonAction(e) { - // Disable button - e.target.setAttribute('class', 'btn btn-sm disabled'); - e.target.removeEventListener('click', mainButtonAction); - - // Iterate through repos - const repos = network.children; - for (let i = 0; i < repos.length; i++) { - if (repos[i].getElementsByClassName('network-tree').length === 0) continue; // Skip original - - processRepo(repos[i]); +"use strict"; + +const forksDiff = (function () { + // Icons + const starIcon = + ''; + const forkIcon = + ''; + const loadingIcon = + ''; + + // Regex + const diffRegex = + /
[\S\s]*?This branch is[\S\s]*?((?[0-9]*) commits? ahead[\S\s]*?(?[0-9]*) commits? behind|(?[0-9]*) commits? behind|(?[0-9]*) commits? ahead)/; + const starsRegex = /([0-9]+) users? starred this repository/; + const githubUrlRegex = /https?:\/\/github\.com\/.*\/network\/members/; + + const queue = []; + const parallelNum = 3; + + const addSpan = (parent, text, className) => { + const span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(text)); + parent.appendChild(span); + }; + + const processRepo = () => { + const currentRepo = queue.shift(); + + // Add spinner + const spinner = document.createElement("span"); + spinner.innerHTML = loadingIcon; + currentRepo.appendChild(spinner); + + const request = new XMLHttpRequest(); + request.addEventListener("load", function () { + if (this.status == 429) { + // Rate limited :( + console.log(this.getResponseHeader("Retry-After")); + return; + } + + const body = this.responseText; + currentRepo.removeChild(spinner); + + // Read diff + const diffRegexResult = diffRegex.exec(body); + if (!diffRegexResult) { + addSpan(currentRepo, "is even", "text-gray"); + } else { + const { + groups: { a1, a2, b, c }, + } = diffRegexResult; + + if (a1 && a2) { + addSpan(currentRepo, "+" + a1, "cadd"); + addSpan(currentRepo, " "); + addSpan(currentRepo, "-" + a2, "cdel"); + } else if (b) { + addSpan(currentRepo, "-" + b, "cdel"); + } else if (c) { + addSpan(currentRepo, "+" + c, "cadd"); } + } + + // Read stars + addSpan(currentRepo, " "); + const stars = body.match(starsRegex); + const starIndicator = document.createElement("span"); + starIndicator.innerHTML = starIcon + " " + stars[1]; + currentRepo.appendChild(starIndicator); + + // Process next repo + if (queue.length > 0) { + processRepo(); + } + }); + + // Send request + request.open("GET", currentRepo.getElementsByTagName("a")[2].href); + request.send(); + }; + + const mainButtonAction = (e) => { + // Disable button + e.target.className = "btn ml-2 float-right disabled"; + e.target.removeEventListener("click", mainButtonAction); + + // Iterate through repos + const repos = network.children; + for (let i = 0; i < repos.length; i++) { + if (repos[i].getElementsByClassName("network-tree").length === 0) + continue; // Skip original + + queue.push(repos[i]); } - function addButton() { - const network = document.getElementById('network'); - - // Check if we have at least one div.repo, if not we are on Network page and not Forks page - if (network === null) return; - if (network.querySelector('div.repo') === null) return; - - const mainButton = document.createElement('button'); - mainButton.className = 'btn btn-sm'; - mainButton.style.float = 'right'; - mainButton.innerHTML = forkIcon + ' Load diff'; - mainButton.addEventListener('click', mainButtonAction); - network.insertBefore(mainButton, network.childNodes[0]); - } - - function addReplaceStateEventListener() { - // https://gist.github.com/rudiedirkx/fd568b08d7bffd6bd372 - const _wr = function(type) { - const orig = history[type]; - return function() { - const rv = orig.apply(this, arguments); - const e = new Event(type); - e.arguments = arguments; - window.dispatchEvent(e); - return rv; - }; - }; - history.pushState = _wr('pushState'); - history.replaceState = _wr('replaceState'); + // Start + for (let i = parallelNum - 1; i >= 0; i--) { + processRepo(); } + }; + + const addButton = () => { + const network = document.getElementById("network"); + + // Check if we have at least one div.repo, if not we are on Network page and not Forks page + if (network === null) return; + if (network.querySelector("div.repo") === null) return; + + const mainButton = document.createElement("button"); + mainButton.className = "btn ml-2 float-right"; + mainButton.innerHTML = forkIcon + " Load diff"; + mainButton.addEventListener("click", mainButtonAction); + network.insertBefore(mainButton, network.childNodes[0]); + }; + + const addReplaceStateEventListener = () => { + // https://gist.github.com/rudiedirkx/fd568b08d7bffd6bd372 + const _wr = (type) => { + const orig = history[type]; + return () => { + const rv = orig.apply(this, arguments); + const e = new Event(type); + e.arguments = arguments; + window.dispatchEvent(e); + return rv; + }; + }; + history.pushState = _wr("pushState"); + history.replaceState = _wr("replaceState"); + }; - function replaceStateListener() { - function action() { - addButton(); - document.removeEventListener('pjax:end', action); - } - - if (githubUrlRegex.test(location.href)) { - document.addEventListener('pjax:end', action); - } + const replaceStateListener = () => { + if (githubUrlRegex.test(location.href)) { + addButton(); } + }; - return { - addButton: addButton, - addReplaceStateEventListener: addReplaceStateEventListener, - replaceStateListener: replaceStateListener, - }; + return { + addButton: addButton, + addReplaceStateEventListener: addReplaceStateEventListener, + replaceStateListener: replaceStateListener, + }; })(); -(function() { - // Add 'replaceState' listener - forksDiff.addReplaceStateEventListener(); - window.addEventListener('replaceState', forksDiff.replaceStateListener); - - forksDiff.addButton(); +(function () { + // Add 'replaceState' listener + forksDiff.addReplaceStateEventListener(); + window.addEventListener("replaceState", forksDiff.replaceStateListener); })(); diff --git a/manifest.json b/manifest.json index dccd6c9..182952d 100644 --- a/manifest.json +++ b/manifest.json @@ -1,28 +1,27 @@ { - "manifest_version": 2, - "name": "__MSG_appName__", - "version": "1.1.1", - "description": "__MSG_appDescription__", - "default_locale": "en", - "icons": { - "16": "icons/icon.16.png", - "32": "icons/icon.32.png", - "48": "icons/icon.48.png", - "64": "icons/icon.64.png", - "128": "icons/icon.128.png" - }, - "content_scripts": [ - { - "matches": [ - "*://github.com/*" - ], - "js": [ - "js/inject.js" - ], - "run_at": "document_end" - } - ], - "web_accessible_resources": [ - "js/main.js" - ] + "manifest_version": 3, + "name": "__MSG_appName__", + "version": "1.2.0", + "description": "__MSG_appDescription__", + "default_locale": "en", + "icons": { + "16": "icons/icon.16.png", + "32": "icons/icon.32.png", + "48": "icons/icon.48.png", + "64": "icons/icon.64.png", + "128": "icons/icon.128.png" + }, + "content_scripts": [ + { + "matches": ["*://github.com/*"], + "js": ["js/inject.js"], + "run_at": "document_end" + } + ], + "web_accessible_resources": [ + { + "resources": ["js/main.js"], + "matches": ["*://github.com/*"] + } + ] } diff --git a/pack.sh b/pack.sh index ae5c014..97dc655 100755 --- a/pack.sh +++ b/pack.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -VERSION="1.1.1" +VERSION="1.2.0-chrome" ICONS_SIZES="16 32 48 64 128" OUTPUT_FOLDER=".build"