Skip to content

Instantly share code, notes, and snippets.

@CertainPerformance
Last active October 14, 2019 17:57
Show Gist options
  • Select an option

  • Save CertainPerformance/d16147600ffa63691e88116b5b040f1d to your computer and use it in GitHub Desktop.

Select an option

Save CertainPerformance/d16147600ffa63691e88116b5b040f1d to your computer and use it in GitHub Desktop.

Revisions

  1. CertainPerformance revised this gist Oct 10, 2019. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions Stack-Experiment-Off.user.js
    Original file line number Diff line number Diff line change
    @@ -3,9 +3,8 @@
    // @author CertainPerformance
    // @description Turns off the voting experiment - shows true vote totals on pageload and after voting
    // @description https://meta.stackoverflow.com/questions/390178/new-popup-message-when-voting-on-a-question
    // @version 1.1.0
    // @version 1.1.1
    // @include /^https://stackoverflow\.com/questions/(?:\d+|tagged|search)/
    // @include https://stackoverflow.com/search?q=foo
    // @run-at document-start
    // @grant none
    // ==/UserScript==
  2. CertainPerformance revised this gist Oct 10, 2019. 1 changed file with 98 additions and 34 deletions.
    132 changes: 98 additions & 34 deletions Stack-Experiment-Off.user.js
    Original file line number Diff line number Diff line change
    @@ -3,8 +3,9 @@
    // @author CertainPerformance
    // @description Turns off the voting experiment - shows true vote totals on pageload and after voting
    // @description https://meta.stackoverflow.com/questions/390178/new-popup-message-when-voting-on-a-question
    // @version 1.0.1
    // @include /^https://stackoverflow\.com/questions/\d+/
    // @version 1.1.0
    // @include /^https://stackoverflow\.com/questions/(?:\d+|tagged|search)/
    // @include https://stackoverflow.com/search?q=foo
    // @run-at document-start
    // @grant none
    // ==/UserScript==
    @@ -13,40 +14,103 @@
    // If using Tampermonkey, enable instant script injection via:
    // Settings -> Experimental -> Inject Mode -> Instant

    const nonNullObj = param => typeof param === 'object' && param !== null;
    new MutationObserver((mutations, observer) => {
    // Wait for window.StackExchange.init to be defined, which is done in stub.en.js near the top of the <head>
    if (!window.StackExchange || !window.StackExchange.init) {
    return;
    }
    observer.disconnect();
    const origInit = window.StackExchange.init;
    window.StackExchange.init = function(...args) {
    if (nonNullObj(args[0]) && nonNullObj(args[0].site)) {
    args[0].site.negativeVoteScoreFloor = -10000;
    const fixQuestionPage = () => {
    const nonNullObj = param => typeof param === 'object' && param !== null;
    new MutationObserver((mutations, observer) => {
    // Wait for window.StackExchange.init to be defined, which is done in stub.en.js near the top of the <head>
    if (!window.StackExchange || !window.StackExchange.init) {
    return;
    }
    return origInit.apply(this, args);
    };
    // origInit is not just a plain function, it also has properties assigned to it
    Object.assign(window.StackExchange.init, origInit);
    })
    .observe(document.documentElement, { childList: true, subtree: true });
    observer.disconnect();
    const origInit = window.StackExchange.init;
    window.StackExchange.init = function(...args) {
    if (nonNullObj(args[0]) && nonNullObj(args[0].site)) {
    args[0].site.negativeVoteScoreFloor = -10000;
    }
    return origInit.apply(this, args);
    };
    // origInit is not just a plain function, it also has properties assigned to it
    Object.assign(window.StackExchange.init, origInit);
    })
    .observe(document.documentElement, { childList: true, subtree: true });

    window.addEventListener('DOMContentLoaded', () => {
    // Display true vote counts:
    [...document.querySelectorAll('.js-vote-count')]
    .forEach((voteCountDiv) => {
    if (voteCountDiv.dataset.value) {
    voteCountDiv.textContent = voteCountDiv.dataset.value;
    window.addEventListener('DOMContentLoaded', () => {
    // Display true vote counts:
    [...document.querySelectorAll('.js-vote-count')]
    .forEach((voteCountDiv) => {
    if (voteCountDiv.dataset.value) {
    voteCountDiv.textContent = voteCountDiv.dataset.value;
    }
    });
    // The "Thanks for the vote" message will come from the server - monkeypatch the modal that displays it to keep it from coming up:
    const { helpers } = window.StackExchange;
    const origShowToast = helpers.showToast;
    helpers.showToast = function(...args) {
    if (typeof args[0] === 'string' && args[0].includes('Since this post’s score')) {
    return;
    }
    });
    // The "Thanks for the vote" message will come from the server - monkeypatch the modal that displays it to keep it from coming up:
    const { helpers } = window.StackExchange;
    const origShowToast = helpers.showToast;
    helpers.showToast = function(...args) {
    if (typeof args[0] === 'string' && args[0].includes('Since this post’s score')) {
    return;
    return origShowToast.apply(this, args);
    }
    return origShowToast.apply(this, args);
    });
    };


    const fixQuestionListPage = () => {
    const initScript = [...document.querySelectorAll('script')]
    .find(script => script.textContent.trim().startsWith('StackExchange.init({'));
    if (!initScript) {
    throw new Error('No script with StackExchange.init found');
    }
    });
    const negativeVoteScoreFloorMatch = initScript.textContent.trim().match(/"negativeVoteScoreFloor":([^,])/);
    if (!negativeVoteScoreFloorMatch) {
    // Maybe the experiment has ended:
    console.warn('No negativeVoteScoreFloor found');
    return;
    }
    const negativeVoteScoreFloorStr = negativeVoteScoreFloorMatch[1];
    // negativeVoteScoreFloorStr will be either "0", "-1", or "null"
    if (negativeVoteScoreFloorStr === 'null') {
    // User is part of the control group - scores are not hidden
    return;
    }
    const negativeVoteScoreFloor = Number(negativeVoteScoreFloorStr);
    const voteCountStrongsByQuestionId = {};
    for (const questionSummary of document.querySelectorAll('.question-summary')) {
    const questionId = questionSummary.id.match(/\d+/)[0];
    const voteCountStrong = questionSummary.querySelector('.vote-count-post > strong');
    const voteCount = Number(voteCountStrong.textContent.trim());
    if (voteCount > negativeVoteScoreFloor) {
    // Vote count is higher than the floor, no need to fetch info:
    continue;
    }
    voteCountStrongsByQuestionId[questionId] = voteCountStrong;
    voteCountStrong.textContent = '?';
    }
    const questionIdsStr = Object.keys(voteCountStrongsByQuestionId).join(';');
    console.log(Object.keys(voteCountStrongsByQuestionId).length);
    if (questionIdsStr.length === 0) {
    // No questions exist on this page
    return;
    }
    const paramsArr = [
    ['pagesize', '50'],
    ['key', 'sFEllbEySR32ZrZ1HOacHQ(('],
    ['site', 'stackoverflow'],
    ['filter', '!)8aD2yy2.nPGnjx'], // From https://api.stackexchange.com/docs/questions-by-ids: .wrapper -> items, .question -> { question_id, score }
    ];
    const searchParams = new URLSearchParams(paramsArr);
    const paramsString = `?${searchParams.toString()}`;
    const url = `https://api.stackexchange.com/2.2/questions/${questionIdsStr}${paramsString}`;
    fetch(url)
    .then(res => res.json())
    .then(({ items }) => {
    items.forEach(({ question_id, score }) => {
    voteCountStrongsByQuestionId[question_id].textContent = score;
    });
    });
    };
    if (/\/questions\/\d+/.test(window.location.href)) {
    fixQuestionPage();
    } else {
    window.addEventListener('DOMContentLoaded', fixQuestionListPage);
    }
  3. CertainPerformance revised this gist Oct 10, 2019. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions Stack-Experiment-Off.user.js
    Original file line number Diff line number Diff line change
    @@ -9,6 +9,10 @@
    // @grant none
    // ==/UserScript==

    // IMPORTANT: This script must run before any script on the page does.
    // If using Tampermonkey, enable instant script injection via:
    // Settings -> Experimental -> Inject Mode -> Instant

    const nonNullObj = param => typeof param === 'object' && param !== null;
    new MutationObserver((mutations, observer) => {
    // Wait for window.StackExchange.init to be defined, which is done in stub.en.js near the top of the <head>
  4. CertainPerformance revised this gist Oct 10, 2019. 1 changed file with 12 additions and 6 deletions.
    18 changes: 12 additions & 6 deletions Stack-Experiment-Off.user.js
    Original file line number Diff line number Diff line change
    @@ -3,16 +3,12 @@
    // @author CertainPerformance
    // @description Turns off the voting experiment - shows true vote totals on pageload and after voting
    // @description https://meta.stackoverflow.com/questions/390178/new-popup-message-when-voting-on-a-question
    // @version 1.0.0
    // @version 1.0.1
    // @include /^https://stackoverflow\.com/questions/\d+/
    // @run-at document-start
    // @grant none
    // ==/UserScript==

    // IMPORTANT: This script must run before any script on the page does.
    // If using Tampermonkey, enable instant script injection via:
    // Settings -> Experimental -> Inject Mode -> Instant

    const nonNullObj = param => typeof param === 'object' && param !== null;
    new MutationObserver((mutations, observer) => {
    // Wait for window.StackExchange.init to be defined, which is done in stub.en.js near the top of the <head>
    @@ -33,10 +29,20 @@ new MutationObserver((mutations, observer) => {
    .observe(document.documentElement, { childList: true, subtree: true });

    window.addEventListener('DOMContentLoaded', () => {
    // Display true vote counts:
    [...document.querySelectorAll('.js-vote-count')]
    .forEach((voteCountDiv) => {
    if (voteCountDiv.dataset.value) {
    voteCountDiv.textContent = voteCountDiv.dataset.value;
    }
    });
    });
    // The "Thanks for the vote" message will come from the server - monkeypatch the modal that displays it to keep it from coming up:
    const { helpers } = window.StackExchange;
    const origShowToast = helpers.showToast;
    helpers.showToast = function(...args) {
    if (typeof args[0] === 'string' && args[0].includes('Since this post’s score')) {
    return;
    }
    return origShowToast.apply(this, args);
    }
    });
  5. CertainPerformance revised this gist Oct 9, 2019. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions Stack-Experiment-Off.user.js
    Original file line number Diff line number Diff line change
    @@ -9,6 +9,10 @@
    // @grant none
    // ==/UserScript==

    // IMPORTANT: This script must run before any script on the page does.
    // If using Tampermonkey, enable instant script injection via:
    // Settings -> Experimental -> Inject Mode -> Instant

    const nonNullObj = param => typeof param === 'object' && param !== null;
    new MutationObserver((mutations, observer) => {
    // Wait for window.StackExchange.init to be defined, which is done in stub.en.js near the top of the <head>
  6. CertainPerformance created this gist Oct 9, 2019.
    38 changes: 38 additions & 0 deletions Stack-Experiment-Off.user.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,38 @@
    // ==UserScript==
    // @name Stack Experiment Off
    // @author CertainPerformance
    // @description Turns off the voting experiment - shows true vote totals on pageload and after voting
    // @description https://meta.stackoverflow.com/questions/390178/new-popup-message-when-voting-on-a-question
    // @version 1.0.0
    // @include /^https://stackoverflow\.com/questions/\d+/
    // @run-at document-start
    // @grant none
    // ==/UserScript==

    const nonNullObj = param => typeof param === 'object' && param !== null;
    new MutationObserver((mutations, observer) => {
    // Wait for window.StackExchange.init to be defined, which is done in stub.en.js near the top of the <head>
    if (!window.StackExchange || !window.StackExchange.init) {
    return;
    }
    observer.disconnect();
    const origInit = window.StackExchange.init;
    window.StackExchange.init = function(...args) {
    if (nonNullObj(args[0]) && nonNullObj(args[0].site)) {
    args[0].site.negativeVoteScoreFloor = -10000;
    }
    return origInit.apply(this, args);
    };
    // origInit is not just a plain function, it also has properties assigned to it
    Object.assign(window.StackExchange.init, origInit);
    })
    .observe(document.documentElement, { childList: true, subtree: true });

    window.addEventListener('DOMContentLoaded', () => {
    [...document.querySelectorAll('.js-vote-count')]
    .forEach((voteCountDiv) => {
    if (voteCountDiv.dataset.value) {
    voteCountDiv.textContent = voteCountDiv.dataset.value;
    }
    });
    });