Skip to content

Instantly share code, notes, and snippets.

@curiosag
Created December 8, 2019 21:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save curiosag/baacd035ccd393abee79522fa9c396a1 to your computer and use it in GitHub Desktop.
Save curiosag/baacd035ccd393abee79522fa9c396a1 to your computer and use it in GitHub Desktop.
Ignore low rep user questions on stack overflow (by Tomáš Zato)
// ==UserScript==
// @name Unnamed Script 703272
// @version 1
// @g// ==UserScript==
// @name Ignore low rep user questions
// @namespace 607407
// @include /https?:\/\/(meta\.)?(stackoverflow|askubuntu|[a-z]+\.stackexchange)\.[a-z]{1,3}/.*?/
// @version 2015.12.18.17.54
// @author http://stackoverflow.com/users/607407
// @grant none
// @run-at document-end
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// ==/UserScript==
// Question will be completely hidden if the user reputation is smaller or equal to...
var HIDE_REP = 5; // hiding using CSS class tagged-ignored-hidden
// Question will be de-emphasized if the user reputation is smaller or equal to...
var IGNORE_REP = 30;// Hiding using CSS class tagged-ignored
// Question is not penalized based on reputation if the vote score is greater or equal to...
var SHOW_VOTES = 1;
// What to do with questions tagged as interesting
// Options:
// "KEEP AS IS" - skip the question and take no actions on it
// "TAG IGNORED" - never hide the question completely, just make it semi-transparent
// "TREAT AS OTHERS" - do not check whether the question is or isn't interesting
var INTERESTING_QUESTIONS = "TREAT AS OTHERS";
// Some pesudoclass to simplify the code
function QuestionSummary(html) {
if(html instanceof jQuery) {
this.$ = html;
this.elm = html[0];
}
else {
this.$ = $(html);
this.elm = html;
}
}
defineHtmlGetterSetter(QuestionSummary.prototype, "reputation", ".reputation-score", {get: function(x) {return x.replace("k", "000").replace(/[^0-9]/g, "")*1;}});
defineHtmlGetterSetter(QuestionSummary.prototype, "score", ".vote-count-post strong");
defineHtmlGetterSetter(QuestionSummary.prototype, "title", ".question-hyperlink");
// Get a list of questions
var questions = document.querySelectorAll(".question-summary");
console.log("Score for ",questions.length," questions.");
//console.log(questions);
// This is deferred, so it runs AFTER the official script that marks the questions
function hideLowRepQuestions(questions) {
for(const questionDiv of questions) {
//console.log(summary);
var question = new QuestionSummary(questionDiv);
//question.elm.className = "question-summary";
var is_interesting = INTERESTING_QUESTIONS=="TREAT AS OTHERS"?false:question.elm.classList.contains("tagged-interesting");
if( question.score>=SHOW_VOTES || ( is_interesting && INTERESTING_QUESTIONS=="KEEP AS IS" ) ) {
console.log("Question ", question.title, " has high score (or otherwise interesting) and thus is never ignored.");
return;
}
if(question.elm.classList.contains("tagged-ignored-hidden")) {
console.log("Question ", question.title, " already hidden.");
return;
}
const rep = question.reputation;
console.log("[QUESTION_HIDER:loop]",question.score, question.title, question.reputation);
// Second part of the condition is there to prevent accidental showing of a question
if( rep <= HIDE_REP ) {
if(is_interesting && INTERESTING_QUESTIONS=="TAG IGNORED") {
if(!question.elm.classList.contains("tagged-ignored")) {
question.elm.classList.add("tagged-ignored");
console.log("Not hiding question ",question.title," because it's interesting.", question.elm);
}
}
else {
if(!question.elm.classList.contains("tagged-ignored-hidden")) {
question.elm.classList.add("tagged-ignored-hidden");
console.log("Hiding question ",question.title,".", question.elm);
}
}
}
else if( rep <= IGNORE_REP ) {
if(!question.elm.classList.contains("tagged-ignored")) {
question.elm.classList.add("tagged-ignored");
console.log("Ignoring question ",question.title,".", question.elm);
}
}
}
}
// Wait till official stackexchange script starts modifying the class attributes:
// Shamelessly copied from https://developer.mozilla.org/en/docs/Web/API/MutationObserver
// I never use this anywhere else than userscripts, so I don't remember that
// select the target node
// You might think that this will only work when
// the first question summary is affected by tag filters
// but the truth is the class attribute is allways being set, even when the value would not change
// So this code allways triggers
var target = document.querySelector('#questions');
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if(mutation.type == "attributes") {
if(mutation.attributeName == "class" && mutation.target.classList.contains("question-summary")) {
hideLowRepQuestions([mutation.target]);
}
}
else if(mutation.type == "childList") {
if(mutation.target.id == "questions") {
hideLowRepQuestions(Array.from(mutation.addedNodes).filter((node)=>{return node.classList.contains("question-summary");}))
}
}
//console.log(mutation.type, mutation.attributeName);
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: false, subtree: true, attributeFilter: ["class"] };
// pass in the target node, as well as the observer options
observer.observe(target, config);
// Run at start
hideLowRepQuestions(questions);
/**
* Creates getter and setter for innerHTML of HTML node got by selector disguised under property name.
* this assumes `this.$` property (jQuery object of the actual HTML) and CACHES all selector results!
* */
function defineHtmlGetterSetter(objectProto, name, selector, descriptor) {
if(typeof descriptor=="undefined")
descriptor = {};
if(typeof descriptor.get!="function") {
descriptor.get = function(x){return x;};
}
if(typeof descriptor.set!="function") {
descriptor.set = function(x){return x;};
}
if(descriptor.nocache) {
Object.defineProperty(objectProto, name, {
get: function() {
return descriptor.get(this.$.find(selector).html());
},
set: function(html) {
return descriptor.set(cachedNode(this).html(html));
},
});
}
else {
Object.defineProperty(objectProto, name, {
get: function() {
return descriptor.get(cachedNode(this).html());
},
set: function(html) {
return descriptor.set(cachedNode(this).html(html));
},
});
function cachedNode(instance) {
return instance["_"+name+"_cached"] instanceof jQuery? instance["_"+name+"_cached"] : instance["_"+name+"_cached"]=instance.$.find(selector);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment