Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 56 additions & 26 deletions background.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,70 @@
chrome.browserAction.onClicked.addListener(function (tab) {
var showingRealNames = localStorage['showingRealNames'];
showingRealNames = showingRealNames && JSON.parse(showingRealNames);
const ONE_WEEK = 7 * 24 * 60 * 60 * 1000;

// Create popup HTML for the extension
chrome.action.setPopup({
popup: 'popup.html'
});

// Initialize display mode if not set
chrome.runtime.onInstalled.addListener(async () => {
const result = await chrome.storage.local.get('displayMode');
if (!result.displayMode) {
await chrome.storage.local.set({ displayMode: 'realName' });
}
});

// Replace localStorage with chrome.storage.local
chrome.action.onClicked.addListener(async (tab) => {
const result = await chrome.storage.local.get('showingRealNames');
let showingRealNames = result.showingRealNames;
if (showingRealNames === undefined) {
showingRealNames = true;
}
showingRealNames = !showingRealNames;
localStorage['showingRealNames'] = JSON.stringify(showingRealNames);
chrome.tabs.sendMessage(tab.id, {action: 'toggle', showingRealNames: showingRealNames });
await chrome.storage.local.set({ showingRealNames });
chrome.tabs.sendMessage(tab.id, { action: 'toggle', showingRealNames });
});

var ONE_WEEK = 7 * 24 * 60 * 60 * 1000;
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.action == "get-showingRealNames") {
var showingRealNames = localStorage['showingRealNames'];
showingRealNames = showingRealNames && JSON.parse(showingRealNames);
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "get-showingRealNames") {
chrome.storage.local.get('showingRealNames').then(result => {
let showingRealNames = result.showingRealNames;
if (showingRealNames === undefined) {
showingRealNames = true;
}
sendResponse({showingRealNames: showingRealNames});
}
if (request.action === 'get-real-name') {
var cached = localStorage['user:' + request.username];
if (cached) {
cached = JSON.parse(cached);
if (cached.timestamp > Date.now() - ONE_WEEK) {
sendResponse({cached: cached.realName});
} else {
sendResponse({cached: null});
}
sendResponse({ showingRealNames });
});
return true; // Will respond asynchronously
}

if (request.action === "get-display-mode") {
chrome.storage.local.get('displayMode').then(result => {
sendResponse({ displayMode: result.displayMode || 'realName' });
});
return true; // Will respond asynchronously
}

if (request.action === 'get-real-name') {
chrome.storage.local.get(`user:${request.username}`).then(result => {
const cached = result[`user:${request.username}`];
if (cached && cached.timestamp > Date.now() - ONE_WEEK) {
sendResponse({ cached: cached.realName });
} else {
sendResponse({ cached: null });
}
}
if (request.action === 'set-real-name') {
localStorage['user:' + request.username] = JSON.stringify({
});
return true; // Will respond asynchronously
}

if (request.action === 'set-real-name') {
chrome.storage.local.set({
[`user:${request.username}`]: {
realName: request.realName,
timestamp: Date.now()
});
}
}).then(() => {
sendResponse({});
}
});
return true; // Will respond asynchronously
}
});
102 changes: 65 additions & 37 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,78 @@
'use strict';

var url = require('url');
var request = require('then-request');
let displayMode = 'realName';
const realNames = new Map();

var showingRealNames = true;
var realNames = {
};

function loadRealName(username) {
if (realNames[username ]) return;
realNames[username] = username;
chrome.runtime.sendMessage({action: "get-real-name", username: username}, function(response) {
if (response && response.cached) {
realNames[username] = response.cached;
async function loadRealName(username) {
if (realNames.has(username)) return;
realNames.set(username, username);

try {
const response = await chrome.runtime.sendMessage({action: "get-real-name", username});
if (response?.cached) {
realNames.set(username, response.cached);
update();
return;
}
request('GET', url.resolve('https://api.github.com/users/', username)).getBody().done(function (res) {
res = JSON.parse(res);
if (res.name) {
realNames[username] = res.name;
chrome.runtime.sendMessage({action: "set-real-name", username: username, realName: res.name}, function(response) {
});
}
update();
});
});

const res = await fetch(`https://api.github.com/users/${username}`);
const data = await res.json();

if (data.name) {
realNames.set(username, data.name);
await chrome.runtime.sendMessage({
action: "set-real-name",
username,
realName: data.name
});
}
update();
} catch (error) {
console.error(`Error loading real name for ${username}:`, error);
}
}

function formatName(username, shouldAt) {
const realName = realNames.get(username);

switch (displayMode) {
case 'realName':
return `${shouldAt ? '@' : ''}${realName}`;
case 'userName':
return `${shouldAt ? '@' : ''}${username}`;
case 'both':
return realName !== username ? `${shouldAt ? '@' : ''}${realName} (${!shouldAt ? '@' : ''}${username})` : `${shouldAt ? '@' : ''}${username}`;
default:
return username;
}
}

chrome.runtime.sendMessage({action: "get-showingRealNames"}, function(response) {
showingRealNames = response.showingRealNames;
// Initialize display mode
chrome.runtime.sendMessage({action: "get-display-mode"}, response => {
displayMode = response.displayMode;
update();
setInterval(update, 1000);
});

// Use MutationObserver instead of setInterval for better performance
const observer = new MutationObserver(() => {
requestAnimationFrame(update);
});

observer.observe(document.body, {
childList: true,
subtree: true
});

function updateList(list, filter, getUsername, shouldAt) {
for (var i = 0; i < list.length; i++) {
if (filter(list[i])) {
var username = getUsername(list[i]);
for (const element of list) {
if (filter(element)) {
const username = getUsername(element);
loadRealName(username);
if (showingRealNames && realNames[username] && realNames[username] !== username) {
list[i].textContent = realNames[username];
} else {
list[i].textContent = (shouldAt ? '@' : '') + username;
}
element.textContent = formatName(username, shouldAt);
}
}
}

function update() {
updateList(document.getElementsByClassName('author'), function (author) {
return author.hasAttribute('href');
Expand All @@ -61,7 +87,9 @@ function update() {
updateList(document.getElementsByClassName('user-mention'), function (mention) {
return mention.hasAttribute('href');
}, function (mention) {
return /\/([^\/]+)$/.exec(mention.getAttribute('href'))[1];
const href = mention.getAttribute('href');
const username = href.split('/').pop().split('?')[0];
return username || '';
}, true);
updateList(document.getElementsByClassName('commit-author'), function (author) {
return true;
Expand Down Expand Up @@ -126,9 +154,9 @@ function update() {
}

update();
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (message.action === 'toggle') {
showingRealNames = message.showingRealNames;
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === 'updateDisplayMode') {
displayMode = message.displayMode;
update();
}
});
33 changes: 22 additions & 11 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,34 @@
"128": "icon.png"
},
"version": "1.3.1",
"manifest_version": 3,
"background": {
"scripts": ["background.js"],
"persistent": false
"service_worker": "background.js",
"type": "module"
},
"browser_action": {
"action": {
"default_icon": "icon.png",
"default_title": "Toggle using real GitHub real names"
"default_title": "GitHub Name Display Options",
"default_popup": "popup.html"
},
"content_scripts" : [
"content_scripts": [
{
"matches" : [
"https://github.com/*"
"matches": [
"https://github.com/*"
],
"js" : [ "contentscript.js" ],
"run_at" : "document_idle",
"all_frames" : false
"js": ["contentscript.js"],
"run_at": "document_idle",
"all_frames": false
}
],
"manifest_version": 2
"permissions": [
"storage",
"tabs"
],
"host_permissions": [
"https://github.com/*"
],
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'"
}
}
15 changes: 8 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
{
"name": "github-real-names",
"version": "0.0.0",
"description": "plugin for Google Chrome that adds a button to toggle showing real names instead of usernames on GitHub",
"version": "1.3.1",
"description": "Chrome extension that adds a button to toggle showing real names instead of usernames on GitHub",
"type": "module",
"dependencies": {
"he": "^0.5.0",
"then-request": "^1.0.0"
"he": "^1.2.0"
},
"devDependencies": {
"browserify": "^16.1.1"
"esbuild": "^0.19.0"
},
"scripts": {
"postinstall": "browserify index.js > contentscript.js"
"build": "esbuild index.js --bundle --outfile=contentscript.js --format=esm --target=chrome110"
},
"repository": {
"type": "git",
"url": "https://github.com/ForbesLindesay/github-real-names.git"
},
"author": "ForbesLindesay",
"license": "MIT"
"license": "MIT",
"packageManager": "[email protected]+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
}
46 changes: 46 additions & 0 deletions popup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<style>
body {
width: 200px;
padding: 10px;
font-family: system-ui, -apple-system, sans-serif;
}
.radio-group {
display: flex;
flex-direction: column;
gap: 8px;
}
label {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
}
h3 {
margin-top: 0;
margin-bottom: 12px;
color: #24292f;
}
</style>
</head>
<body>
<h3>Display Names As</h3>
<div class="radio-group">
<label>
<input type="radio" name="displayMode" value="realName">
Real Name
</label>
<label>
<input type="radio" name="displayMode" value="userName">
Username
</label>
<label>
<input type="radio" name="displayMode" value="both">
Real Name (@username)
</label>
</div>
<script src="popup.js"></script>
</body>
</html>
22 changes: 22 additions & 0 deletions popup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Initialize radio buttons
chrome.storage.local.get('displayMode', (result) => {
const displayMode = result.displayMode || 'realName';
document.querySelector(`input[value="${displayMode}"]`).checked = true;
});

// Add change listener to radio buttons
document.querySelectorAll('input[name="displayMode"]').forEach(radio => {
radio.addEventListener('change', async (e) => {
if (e.target.checked) {
await chrome.storage.local.set({ displayMode: e.target.value });
// Notify all tabs to update
const tabs = await chrome.tabs.query({ url: 'https://github.com/*' });
tabs.forEach(tab => {
chrome.tabs.sendMessage(tab.id, {
action: 'updateDisplayMode',
displayMode: e.target.value
});
});
}
});
});
Loading