6

About

The main purpose of this script is to prevent one from accidentally interacting with questions/answers posted by a sock of their own (but it can also be used to avoid interacting with posts from other users, not necessarily sockpuppet accounts).

This is useful if you post questions/answers from a sockpuppet and use your main account to view them. You might not pay attention to the fact that you're using the main account and accidentally interact with the post (e.g., vote on answers by others, leave comments, etc.). It works as follows:

  • If the post is a question, it disables:

    • Vote buttons (up and down) on the question and all answers.
    • Flag buttons on the question and all answers.
    • The Close button.
    • The Protect/Unprotect button.
    • The Start a bounty link.
    • The Post Your Answer button
    • The Edit link on the question and all answers.
    • The Add a comment link on the question and all answers.
  • If the post is an answer, it disables:

    • Vote buttons (up and down) on the answer only.
    • The Flag button on the answer only.
    • The Edit link on the answer only.
    • The Add a comment link on the answer only.

Screenshot:

Disabled elements on question and answer.

Platform:

Tested on Chrome and Firefox using Tampermonkey but should probably work with any modern browser with JavaScript enabled.

Code:

// ==UserScript==
// @name        SE: Don't let me interact with this user's posts
// @version     1.2
// @namespace   https://stackapps.com/users/80115/41686d6564
// @description This scripts disables interactions with posts by certain users (avoid accidentally interacting with your own sockpuppet)
// @author      https://stackapps.com/users/80115/41686d6564
// @match       *://stackoverflow.com/questions/*
// @match       *://meta.stackoverflow.com/questions/*
// ==/UserScript==

// Add user IDs here
var usersToAvoid = ['userId1', 'userId2'];

$(window).on('load', function() {
    "use strict";

    let question = $('#question');
    if (question.length == 0)
        return;

    if (!checkPost(question, true)) {
        $('#answers').children('div.answer').each(function() {
            let answer = $(this);
            checkPost(answer, false);
        });
    }
});

function checkPost(post, isQuestion) {
    let ownerUserDetails = post.find('div.user-details[itemprop="author"]');
    if (ownerUserDetails == 0)
        return false;

    let url = ownerUserDetails.find('a')[0].getAttribute("href");
    let userId = url.match(/^\/users\/(\d+)/)[1];

    if (usersToAvoid.includes(userId)) {
        let scope = isQuestion ? post.parent() : post;

        scope.find('button.js-vote-up-btn').prop("disabled", true);
        scope.find('button.js-vote-down-btn').prop("disabled", true);
        scope.find('button.js-flag-post-link').prop("disabled", true);
        replaceLinkWithDisabledButton(scope.find('a.js-edit-post'), 'js-edit-post');
        replaceLinkWithDisabledButton(scope.find('a.js-add-link.comments-link'), 'js-add-link.comments-link');

        if (isQuestion) {
            $('button.js-close-question-link').prop("disabled", true);
            scope.find('button[id=btnProtectLoggedIn]').prop("disabled", true);
            scope.find('button[id=btnUnprotectLoggedIn]').prop("disabled", true);
            replaceLinkWithDisabledButton($('a[id=edit-tags]'), '');
            replaceLinkWithDisabledButton(scope.find('a.js-suggest-edit-post'), 'js-suggest-edit-post');
            replaceLinkWithDisabledButton($('a.bounty-link'), 'bounty-link');
            $('button[id=submit-button]').prop("disabled", true);
        }

        return true;
    }

    return false;
}

function replaceLinkWithDisabledButton(link, _class) {
    link.replaceWith(function() {
        return `<button type="button" class="${_class} s-btn s-btn__link" disabled="">${$(this).text()}</button>`;
    });
}

Note: This version supports only one site and its meta (default is Stack Overflow). I wrote another version that works with all sites but I posted it separately as an answer because it needs to make an API call upon visiting any /questions/* page. If you only want to support one site, use this version instead because it'll be faster.

If you have any suggestions, please leave them below.

1

1 Answer 1

2

Here's v2, which uses account IDs instead of user IDs and works across all sites. It does, however, need to make an API request upon visiting any /questions/* page.

// ==UserScript==
// @name        SE: Don't let me interact with this user's posts
// @version     2.1
// @namespace   https://stackapps.com/users/80115/41686d6564
// @description This scripts disables interactions with posts by certain users (avoid accidentally interacting with your own sockpoppet)
// @author      https://stackapps.com/users/80115/41686d6564
// @match        *://*.stackexchange.com/questions/*
// @match        *://*.stackoverflow.com/questions/*
// @match        *://*.serverfault.com/questions/*
// @match        *://*.askubuntu.com/questions/*
// @match        *://*.mathoverflow.net/questions/*
// @match        *://*.stackapps.com/questions/*
// @match        *://*.superuser.com/questions/*

// ==/UserScript==

// Add account IDs here
var usersToAvoid = [];

$(window).on('load', function() {
    "use strict";

    let question = $('#question');
    if (question.length == 0)
        return;

    let postsUserInfo = [];
    // Get question's author user ID.
    let questionUserId = getUserId(question);
    if (questionUserId != null)
        postsUserInfo.push({"post": question, "userId": questionUserId, "accountId": null});

    // Get answers' authors user IDs.
    $('#answers').children('div.answer').each(function() {
        let answer = $(this);
        let answerUserId = getUserId(answer);
        if (answerUserId != null)
            postsUserInfo.push({"post": answer, "userId": answerUserId, "accountId": null});
    });

    // Make an API call to retrieve the corresponding account IDs.
    let joinedUserIds = [...new Set(postsUserInfo.map(item => item.userId))].join(";");
    $.get(`https://api.stackexchange.com/2.3/users/${joinedUserIds}?site=${window.location.hostname}`, function(data) {
        data.items.forEach(user => {
            postsUserInfo.filter(item => item.userId == user.user_id)
                .forEach(item => item.accountId = user.account_id);
        });

        // Check account IDs and shield matching posts.
        for(const postUserInfo of postsUserInfo) {
            if (usersToAvoid.includes(postUserInfo.accountId)) {
                let isQuestion = postUserInfo.userId == questionUserId;
                shieldPost(postUserInfo.post, isQuestion);
                // Shielding the question also shields all answers. So, no need to continue.
                if (isQuestion)
                    break;
            }
        }
    });
});

function getUserId(post) {
    let ownerUserDetails = post.find('div.user-details[itemprop="author"]');
    if (ownerUserDetails == 0)
        return null;

    let url = ownerUserDetails.find('a')[0].getAttribute("href");
    let userId = url.match(/^\/users\/(\d+)/)[1];
    return userId;
}

function shieldPost(post, isQuestion) {
    let scope = isQuestion ? post.parent() : post;

    scope.find('button.js-vote-up-btn').prop("disabled", true);
    scope.find('button.js-vote-down-btn').prop("disabled", true);
    scope.find('button.js-flag-post-link').prop("disabled", true);
    replaceLinkWithDisabledButton(scope.find('a.js-edit-post'), 'js-edit-post');
    replaceLinkWithDisabledButton(scope.find('a.js-suggest-edit-post'), 'js-suggest-edit-post');
    replaceLinkWithDisabledButton(scope.find('a.js-add-link.comments-link'), 'js-add-link.comments-link');

    if (isQuestion) {
        $('button.js-close-question-link').prop("disabled", true);
        scope.find('button[id=btnProtectLoggedIn]').prop("disabled", true);
        scope.find('button[id=btnUnprotectLoggedIn]').prop("disabled", true);
        replaceLinkWithDisabledButton($('a[id=edit-tags]'), '');
        replaceLinkWithDisabledButton($('a.bounty-link'), 'bounty-link');
        $('button[id=submit-button]').prop("disabled", true);
    }
}

function replaceLinkWithDisabledButton(link, _class) {
    link.replaceWith(function() {
        return `<button type="button" class="${_class} s-btn s-btn__link" disabled="">${$(this).text()}</button>`;
    });
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .