diff --git a/pronoun-assistant/pronoun-assistant.user.js b/pronoun-assistant/pronoun-assistant.user.js
index a47ed0b..d12e103 100644
--- a/pronoun-assistant/pronoun-assistant.user.js
+++ b/pronoun-assistant/pronoun-assistant.user.js
@@ -8,10 +8,24 @@
// @updateURL https://raw.githubusercontent.com/Glorfindel83/SE-Userscripts/master/pronoun-assistant/pronoun-assistant.user.js
// @downloadURL https://raw.githubusercontent.com/Glorfindel83/SE-Userscripts/master/pronoun-assistant/pronoun-assistant.user.js
// @supportURL https://stackapps.com/questions/8440/pronoun-assistant
-// @version 1.4
+// @version 2.1
// @match *://chat.stackexchange.com/rooms/*
// @match *://chat.stackoverflow.com/rooms/*
// @match *://chat.meta.stackexchange.com/rooms/*
+// @match *://*.stackexchange.com/questions/*
+// @match *://*.stackoverflow.com/questions/*
+// @match *://*.superuser.com/questions/*
+// @match *://*.serverfault.com/questions/*
+// @match *://*.askubuntu.com/questions/*
+// @match *://*.stackapps.com/questions/*
+// @match *://*.mathoverflow.net/questions/*
+// @exclude *://*.stackexchange.com/questions/ask
+// @exclude *://*.stackoverflow.com/questions/ask
+// @exclude *://*.superuser.com/questions/ask
+// @exclude *://*.serverfault.com/questions/ask
+// @exclude *://*.askubuntu.com/questions/ask
+// @exclude *://*.stackapps.com/questions/ask
+// @exclude *://*.mathoverflow.net/questions/ask
// @grant GM_addStyle
// @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
// @require https://gist.github.com/raw/2625891/waitForKeyElements.js
@@ -20,9 +34,6 @@
/* global $, waitForKeyElements */
-// NICETOHAVE: on main/meta sites as well; right now, there are very few users
-// who have indicated their pronouns in their main/meta profile.
-
GM_addStyle(`
.tiny-signature {
display: inline-flex;
@@ -37,6 +48,7 @@ GM_addStyle(`
.pronouns {
color: #777;
+ padding-left: 5px;
}
`)
@@ -50,7 +62,7 @@ let allPronouns = [
].join("|");
let pronounListRegex = new RegExp('\\W*((' + allPronouns + ')(\\s*/\\s*(' + allPronouns + '))+)\\W*', 'i');
let myPronounIsRegex = /(https?:\/\/)?(my\.)?pronoun\.is\/([\w/]+)/i;
-let explicitPronounsRegex = /pronouns:\s*([^.\n]*)(\.|\n|$)/im;
+let explicitPronounsRegex = /pronouns:\s*([^.\n)]*)(\.|\n|\)|$)/im;
// Keys: user IDs
// Values: either a list of DOM elements (specifically, the anchors to chat profiles)
@@ -59,17 +71,25 @@ var users = {};
// TODO: cache in local storage
// Adds pronoun information to a user's 'signature' in chat.
-function showPronouns(element, pronouns) {
+function showPronounsForChat(element, pronouns) {
if (pronouns == "") {
return;
}
// the element might contain both a tiny and a full signature
element.find("div.username").each(function (index, usernameElement) {
usernameElement.innerHTML = '' + usernameElement.innerHTML + '
'
- + '' + pronouns + '';
+ + '' + pronouns.replace(/(<([^>]+)>)/ig, "") + '';
});
}
+//
+function showPronouns(element, pronouns) {
+ if (pronouns == "") {
+ return;
+ }
+ element.after($('' + pronouns.replace(/(<([^>]+)>)/ig, "") + ''));
+}
+
// Check the user's 'about' in their chat profile for pronoun indicators
function getPronouns(aboutMe) {
// Link to Pronoun Island, e.g.
@@ -100,6 +120,19 @@ function getPronouns(aboutMe) {
return "";
}
+// Converts the hostname (e.g. "meta.stackexchange.com") into the site parameter for the API ("meta")
+function getSite(hostname) {
+ if (hostname.contains(".stackexchange.com")) {
+ return hostname.split(".stackexchange.com")[0];
+ } else if (hostname.contains(".com")) {
+ return hostname.split(".com")[0];
+ } else {
+ // MathOverflow, MathOverflow Meta
+ return hostname;
+ }
+}
+
+// Chat signatures
waitForKeyElements("a.signature", function(jNode) {
let userID = jNode.attr("href").split("/users/")[1];
if (!users.hasOwnProperty(userID)) {
@@ -109,13 +142,78 @@ waitForKeyElements("a.signature", function(jNode) {
$.get("https://" + location.host + "/users/thumbs/" + userID + "?showUsage=true", function(data) {
let pronouns = data.user_message == null ? "" : getPronouns(data.user_message);
users[userID].forEach(function (element) {
- showPronouns(element, pronouns);
+ showPronounsForChat(element, pronouns);
});
users[userID] = pronouns;
});
} else if (typeof users[userID] == 'string') {
- showPronouns(jNode, users[userID]);
+ // We already have the pronouns, we can just use them.
+ showPronounsForChat(jNode, users[userID]);
} else {
+ // User appearing multiple times, their profile is already being fetched.
users[userID].push(jNode);
}
});
+
+// Q&A site user cards & comment usernames
+(async () => {
+ const sleep = async (ms) => {
+ return new Promise(resolve => {
+ setTimeout(resolve, ms);
+ });
+ };
+
+ const userIds = [];
+ const profiles = {};
+
+ const $userElements = $("div.user-details > a, a.comment-user");
+
+ // Grab all the user IDs out of a page first. We'll go back over them later to add pronouns in.
+ $userElements.each(function() {
+ const link = $(this).attr("href");
+ if (!link.startsWith("/users/")) {
+ // not a user card, but a community wiki post
+ return;
+ }
+ const userId = parseInt(link.split("/users/")[1]);
+ if (userIds.indexOf(userId) === -1) {
+ userIds.push(userId);
+ }
+ });
+
+ // Split the list into 100-item pages and grab profiles for each page.
+ // This works because splice modifies the userIds array in-place, removing elements from the front and
+ // returning them into the `page` variable. When we've used them all, the array will be empty.
+ while (userIds.length > 0) {
+ const page = userIds.splice(0, 100);
+
+ const resp = await fetch("https://api.stackexchange.com/2.2/users/" + page.join(';') + "?site=" + getSite(location.hostname)
+ + "&key=L8n*CvRX3ZsedRQicxnjIA((&filter=!23IboywNfWUzv_nydJbn*&pagesize=100");
+ const data = await resp.json();
+ if (typeof data.items != 'undefined') {
+ data.items.forEach(i => {
+ profiles[i.user_id] = i.about_me;
+ });
+ }
+
+ if (data.backoff) {
+ // Respect backoffs, not just pronouns.
+ await sleep(data.backoff * 1000);
+ }
+ }
+
+ $userElements.each(function() {
+ const link = $(this).attr("href");
+ const userId = parseInt(link.split("/users/")[1]);
+ if (!users.hasOwnProperty(userId)) {
+ // No pronouns calculated yet, we need to calculate and store them.
+ users[userId] = getPronouns(profiles[userId]);
+ showPronouns($(this), users[userId]);
+ }
+ else {
+ // We already have the pronouns, we can just use them.
+ showPronouns($(this), users[userId]);
+ }
+ });
+})();
+