// ==UserScript==
// @name        Bookmark Users
// @version     1.1.1
// @author      Martijn Pieters
// @description Shows what user bookmarked a question. Fetches the bookmarking users from the StackExchange data explorer (data can be up to a week old)
// @homepage    https://github.com/mjpieters/SO-userscripts
// @supportURL  https://github.com/mjpieters/SO-userscripts/issues
// @match       http*://*.stackoverflow.com/questions/*
// @match       http*://*.serverfault.com/questions/*
// @match       http*://*.superuser.com/questions/*
// @match       http*://*.askubuntu.com/questions/*
// @match       http*://*.mathoverflow.net/questions/*
// @match       http*://*.stackexchange.com/questions/*
// @namespace   https://github.com/mjpieters/SO-userscripts
// @downloadURL https://github.com/mjpieters/SO-userscripts/raw/v1.1.1/dist/bookmark-users.user.js
// @updateURL   https://github.com/mjpieters/SO-userscripts/raw/main/dist/bookmark-users.user.js
// @grant       GM_xmlhttpRequest
// @grant       GM_addStyle
// @connect     data.stackexchange.com
// ==/UserScript==

(()=>{"use strict";var e={584:(e,s)=>{Object.defineProperty(s,"__esModule",{value:!0}),s.userStyles=s.controllerId=s.sedeQueryId=s.sedeUrl=s.minimalUserFilter=s.seApiUrl=s.seApiKey=void 0,s.seApiKey="9VvY5KWke5mKcflYkx)NDw((",s.seApiUrl="https://api.stackexchange.com/2.3",s.minimalUserFilter="!)69QNaSIc2a*QW(ccD0ph0dVbliY",s.sedeUrl="https://data.stackexchange.com/",s.sedeQueryId="1894927",s.controllerId="us-bookmarkers",s.userStyles=`\n.${s.controllerId}-content { min-height: min-content; }\n.${s.controllerId}-popover .s-user-card__minimal .anonymous-gravatar {\n  zoom:0.5;\n  -moz-transform:scale(0.5);\n  -moz-transform-origin: 0 0;\n}\n.${s.controllerId}-popover .s-user-card__minimal .s-user-card--time {\n  font-variant-numeric: tabular-nums;\n}\n`},730:(e,s,t)=>{Object.defineProperty(s,"__esModule",{value:!0}),s.BookmarkersController=void 0;const r=t(584),a=t(8),n=t(432),o=`\n  <button\n    class="s-btn s-btn__unset c-pointer py4"\n    data-controller="s-tooltip ${r.controllerId}"\n    data-s-popover-toggle-class="fc-yellow-600"\n    data-s-tooltip-placement="right"\n    data-action="click->s-popover#toggle s-popover:show->${r.controllerId}#showBookmarkers"\n    aria-pressed="false"\n    title="Show who bookmarked this question."\n  ></button>\n`,i=`\n  <div\n    class="${r.controllerId}-popover s-popover"\n    role="dialog"\n    aria-hidden="true"\n  >\n    <div class="s-popover--arrow"></div>\n    <div class="m4 hmx3 wmx100 overflow-x-hidden overflow-y-auto">\n      <div\n        class="${r.controllerId}-popover-inner d-flex fd-column flex__center gs8 gsy"\n      >\n        <ul class="list-reset flex--item mr-auto"></ul>\n        <div class="s-spinner s-spinner__sm flex--item">\n          <div class="v-visible-sr">Loading…</div>\n        </div>\n      </div>\n    </div>\n  </div>\n`;class l extends Stacks.StacksController{constructor(){super(...arguments),this.state="initial"}static attach(e){e&&e.querySelector(".js-bookmark-count")?.offsetParent&&(l.style||(l.style=GM_addStyle(r.userStyles)),e.insertAdjacentHTML("afterend",o),e.nextElementSibling?.insertAdjacentElement("beforeend",Svg.Person()[0]),Stacks.application.register(r.controllerId,l))}connect(){"initial"===this.state&&(this.state="attached",Stacks.attachPopover(this.element,i),this.popoverElement=document.getElementById(this.element.getAttribute("aria-controls")))}async showBookmarkers(){if("attached"!==this.state)return;this.state="loading";const e=this.popoverElement.querySelector("ul"),s=StackExchange.question.getQuestionId(),t=await(0,a.fetchBookmarkers)(s);if(t.length){const s=new Map(t.map((e=>[e.userId,e.date])));for await(const r of(0,n.fetchUsers)(t.map((e=>e.userId)),!0))e.insertAdjacentHTML("beforeend",`<li class="mb4">${r.toHTML(s.get(r.user_id.toFixed(0)))}</li>`)}else e.insertAdjacentHTML("beforeend",'<li class="mb4 fs-italic">No bookmarkers known (yet)</li>'),e.classList.add("mx-auto");this.state="loaded",this.popoverElement.querySelector(".s-spinner").remove()}}s.BookmarkersController=l,l.style=null},8:(e,s,t)=>{Object.defineProperty(s,"__esModule",{value:!0}),s.fetchBookmarkers=void 0;const r=t(584),a=t(209);s.fetchBookmarkers=function(e){const s=(0,a.getSiteId)();return new Promise(((t,a)=>{GM_xmlhttpRequest({method:"GET",url:`${r.sedeUrl}/${s}/csv/${r.sedeQueryId}?postId=${e}`,fetch:!0,onload:e=>{200!==e.status&&a(new Error(`invalid response ${e}`));const s=e.responseText.split(/\r?\n/).filter(Boolean);s.shift(),t(s.map((e=>{const[s,t]=e.replaceAll('"',"").split(",");return{date:s.split(" ")[0],userId:t}})))}})}))}},432:(e,s,t)=>{Object.defineProperty(s,"__esModule",{value:!0}),s.fetchUsers=void 0;const r=t(209),a=t(584),n=new Intl.NumberFormat("en-US",{notation:"compact",maximumSignificantDigits:3}),o=new Intl.NumberFormat("en-US",{useGrouping:!0});class i{get badges(){const e=[];switch(this.is_employee&&e.push('<span class="s-badge s-badge__staff s-badge__xs">Staff</span>'),this.user_type){case"moderator":e.push('<span class="s-badge s-badge__moderator s-badge__xs">Mod</span>');break;case"team_admin":e.push('<span class="s-badge s-badge__admin s-badge__xs">Admin</span>')}return e.join(" ")}get abbreviated_reputation(){return this.reputation<1e4?o.format(this.reputation):n.format(this.reputation).toLowerCase()}toHTML(e){return`\n      <div class="s-user-card s-user-card__minimal">\n        <time class="s-user-card--time">${e}</time>\n        <a href="${this.link}" class="s-avatar s-user-card--avatar">\n          <img class="s-avatar--image" src="${this.profile_image}" />\n        </a>\n        <div class="s-user-card--info">\n          <a href="${this.link}" class="s-user-card--link"\n            >${this.display_name} ${this.badges}</a\n          >\n          <ul class="s-user-card--awards">\n            <li\n              class="s-user-card--rep"\n              title="reputation score ${o.format(this.reputation)}"\n            >\n              ${this.abbreviated_reputation}\n            </li>\n          </ul>\n        </div>\n      </div>\n    `}}class l extends i{constructor(e){super(),this.user_id=parseInt(e),this.link=`/users/${e}`}toHTML(e){return StackExchange.options.user.isModerator?`\n        <div class="s-user-card s-user-card__minimal s-user-card__deleted">\n          <time class="s-user-card--time">${e}</time>\n          <a href="${this.link}" class="s-avatar s-user-card--avatar">\n            <span class="anonymous-gravatar"></span>\n          </a>\n          <div class="s-user-card--info">\n            <a href="${this.link}" class="s-user-card--link"\n              >user${this.user_id}</a\n            >\n          </div>\n        </div>\n      `:`\n      <div class="s-user-card s-user-card__minimal s-user-card__deleted">\n        <time class="s-user-card--time">${e}</time>\n        <div class="s-avatar s-user-card--avatar">\n          <span class="anonymous-gravatar"></span>\n        </a>\n        <div class="s-user-card--info">\n          <div class="s-user-card--link">user${this.user_id}</a>\n        </div>\n      </div>\n    `}}s.fetchUsers=async function*(e,s=!1){for(;e.length>0;){const t=e.splice(0,100);e=e.splice(100);const n=await(0,r.seApiFetch)(`users/${t.join(";")}`,a.minimalUserFilter),o=new Map(n.map((e=>[e.user_id.toFixed(0),Object.assign(new i,e)])));yield*t.reduce(((e,t)=>{let r=o.get(t);return void 0===r&&s&&(r=new l(t)),r?[...e,r]:e}),[])}}},209:(e,s,t)=>{Object.defineProperty(s,"__esModule",{value:!0}),s.seApiFetch=s.delay=s.getSiteId=void 0;const r=t(584);function a(){return location.hostname.replace(/(\.stackexchange)?\.com$/,"")}function n(e){return new Promise((s=>setTimeout(s,e)))}s.getSiteId=a,s.delay=n;const o=new Map;s.seApiFetch=async function(e,...[s]){const t=new URL(`${r.seApiUrl}/${e}`);t.search=new URLSearchParams({...s&&{filter:s},key:r.seApiKey,site:a(),pagesize:"100"}).toString();const i=(o.get(e)??0)-(new Date).getTime();i>0&&await n(i);const l=await fetch(t.toString()),c=await l.json();if(o.set(e,(new Date).getTime()+c.backoff??0),c.error_id)throw new Error(`${c.error_name} (${c.error_id}): ${c.error_message}`);return c.items}}},s={};function t(r){var a=s[r];if(void 0!==a)return a.exports;var n=s[r]={exports:{}};return e[r](n,n.exports,t),n.exports}(()=>{const e=t(730);StackExchange.ready((()=>e.BookmarkersController.attach(document.querySelector(".js-bookmark-btn"))))})()})();
//# sourceMappingURL=https://github.com/mjpieters/SO-userscripts/raw/v1.1.1/dist/bookmark-users.map