// ==UserScript==
// @name meneame.net - Mostrar negativizadores de meneos
// @namespace http://tampermonkey.net/
// @version 0.11
// @description Muestra una lista de los usuarios que han votado negativo un meneo.
// @author ᵒᶜʰᵒᶜᵉʳᵒˢ
// @include *.meneame.net/*
// @connect meneame.net
// @icon https://www.meneame.net/favicon.ico
// @grant GM.xmlHttpRequest
// @grant GM_addStyle
// @license GNU GPLv3
// ==/UserScript==
// RECOMENDADO USAR JUNTO AL CSS DE @Ergo: https://userstyles.world/style/1811
// ---- SCRIPT values ----
const COLUMNS = 3;
const ALIGNMENT = 'left'; // right / left
const ORDER_DATE = 'ASC'; // ASC / DESC
const NAME_LENGTH_PIXELS = 105;
// ---- API values ----
const NEGATIVE_COUNTER_CLASS = '.negative-vote-number';
const NEGATIVE_HEADER = '.news-details';
const NEGATIVE_HEADER_CONTENT = 'votos negativos:';
const VOTERS_LIST = '.voters-list';
const VOTER = 'a + span';
const NEWS_SUMMARY = '.news-summary'
const STORY_BLOG = '.story-blog';
const STORY_BLOG_INSERTION = '.col-md-8.col-md-offset-1';
const URL_VOTERS = 'https://www.meneame.net/backend/meneos.php?id=MENEO_ID&p=PAGE_COUNTER';
const URL_USER_VOTES = 'https://www.meneame.net/user/#USERNAME/shaken';
const USER_VOTES_HREF = "<a href='"+ URL_USER_VOTES + "' title='Noticias votadas por #USERNAME'>#SHAKEN_TEXT</a>";
const NEGATIVE_OPTIONS = [
'antigua',
'bulo',
'cansina',
'copia/plagio',
'duplicada',
'errónea',
'irrelevante',
'microblogging',
'spam',
'muro de pago',
'sensacionalista',
];
const AVATAR_TOOLTIP_CLASS = 'avatar tooltip u:ID_USUARIO lazy';
const negativeArticleCSSSuffix = '_Article';
const negativeArticleCSSPrefix = 'negative_class_';
const negativeClassHeader = negativeArticleCSSPrefix + "header";
const negativeClassColumnsContainer = negativeArticleCSSPrefix + 'columns_container'
const divNegativizators = "<div class='" + negativeClassHeader + "'>HEADER</div><BR><div class='" + negativeClassColumnsContainer + "'><div class='" + negativeArticleCSSPrefix + "voters'>LIST_NEG</div></div>";
const divNegativizator = "<div class='" + negativeArticleCSSPrefix + "voter'><p class='" + negativeArticleCSSPrefix + "what WHAT'>WHAT</p><p class='" + negativeArticleCSSPrefix + "who'>WHO</p><p class='" + negativeArticleCSSPrefix + "when'>WHEN</p></div>";
const NegativizatorsCSS = "." + negativeClassHeader + " {text-align: left; margin-left: 20px;} ." + negativeClassColumnsContainer + " {margin-left: 20px; margin-right: 20px; text-align: center;} ." + negativeArticleCSSPrefix + "voters {text-align: right; column-count: COLUMNS; column-rule-style: solid; column-gap: 5px;} ." + negativeArticleCSSPrefix + "voter {text-align: right; font-size: smaller; column-count: 3; column-width: 60px;} .negative_class_who {width:NAME_LENGTH_PIXELSpx;white-space:nowrap;overflow:hidden;text-overflow:'…';}";
var Total_Negativizators = 0;
var Array_Voters = [];
var Article = false;
ListNegativizators();
function ListNegativizators() {
if (link_id > 0 && IsArticle() && HasNegatives()) {
Article = true;
ShowList();
} else {
if (link_id > 0 && document.querySelector(NEGATIVE_COUNTER_CLASS) && parseInt(document.querySelector(NEGATIVE_COUNTER_CLASS).textContent,10) > 0) ShowList();
}
}
function IsArticle() {
return document.querySelectorAll(STORY_BLOG).length > 0 ? true : false;
}
async function HasNegatives() {
await GM.xmlHttpRequest(
{method: "GET", url: url_votes(1), responseType: "document", onload: function(result) {
var xmlDoc = new DOMParser().parseFromString(result.responseText, "text/html");
return xmlDoc.querySelector(NEGATIVE_HEADER).innerHTML.includes(NEGATIVE_HEADER_CONTENT) ? true : false;
}})
}
async function ShowList() {
var negative_header_content = '';
var voters_page_counter = 1;
var MaxPages = 0;
while (voters_page_counter > 0) {
await GM.xmlHttpRequest(
{method: "GET", url: url_votes(voters_page_counter), responseType: "document", onload: function(result) {
var xmlDoc = new DOMParser().parseFromString(result.responseText, "text/html");
if (negative_header_content == '') {
negative_header_content = ApplyCSS2Header(xmlDoc.querySelector(NEGATIVE_HEADER).innerHTML);
MaxPages = parseInt(xmlDoc.getElementsByClassName('pages')[0].lastChild.text, 10);
}
var node = xmlDoc.querySelector(VOTERS_LIST);
(node && node.childElementCount > 0) ? AddPageNegativizators(node) : voters_page_counter = -1;
}
}
);
++voters_page_counter;
if (voters_page_counter > MaxPages) voters_page_counter = 0;
}
InsertNegativizators(negative_header_content);
}
function AddPageNegativizators(page_node) {
var node_neg = page_node.querySelectorAll(VOTER);
if (node_neg && node_neg.length > 0) {
node_neg.forEach( function(page_node) {
divNegativeVoter(page_node.textContent, page_node.previousElementSibling.title, insertClassAvatar(page_node.previousElementSibling.childNodes[0]));
});
}
}
function InsertNegativizators(header_content) {
if (Total_Negativizators > 0) {
GM_addStyle(NegativizatorsCSS.replace('COLUMNS',COLUMNS).replace('text-align: right','text-align: ' + ALIGNMENT).replace('NAME_LENGTH_PIXELS',NAME_LENGTH_PIXELS));
if (ORDER_DATE == 'ASC') Array_Voters.sort((a,b) => b.Total_Negativizators - a.Total_Negativizators);
var where_class = NEWS_SUMMARY;
var position = 'afterend';
var what = columnDiv(header_content, ExtractVotersFromArray());
if (Article) {
position='afterbegin';
where_class = STORY_BLOG_INSERTION;
what = what.replace(negativeClassHeader, negativeClassHeader + negativeArticleCSSSuffix).replace(negativeClassColumnsContainer, negativeClassColumnsContainer + negativeArticleCSSSuffix);
}
document.querySelector(where_class).insertAdjacentHTML(position, what);
}
}
function ApplyCSS2Header(strHeader) {
for(var negativeOption of NEGATIVE_OPTIONS) {
strHeader = strHeader.replace(negativeOption,"<span class='" + negativeArticleCSSPrefix + "what " + negativeOption.replaceAll(' ', '_') + "'>" + negativeOption.toUpperCase() + "</span>").replace(NEGATIVE_HEADER_CONTENT,NEGATIVE_HEADER_CONTENT.toUpperCase());
}
return strHeader;
}
function ExtractVotersFromArray() {
var result = '';
for(var voter_div of Array_Voters) {result += voter_div.strData;}
return result;
}
function divNegativeVoter(what, who, avatar) {
var date_lenght = 20;
if ((who.slice(-11)).slice(0,1) == ':') date_lenght = 9;
var when = who.slice(-date_lenght).replace(' UTC','').replace('-202','-2');
var userName = who.slice(0,-1*(date_lenght+2));
who = ALIGNMENT == 'left' ? avatar + ' ' + formatWho(userName) : formatWho(userName) + ' ' + avatar;
++Total_Negativizators;
var strData = divNegativizator.replace('WHAT', what.replaceAll(' ', '_')).replace('WHAT',encloseATagUserVotes(what.toUpperCase(), userName)).replace('WHO', who).replace('WHEN',when);
Array_Voters.push({strData, Total_Negativizators});
}
function encloseATagUserVotes(strData, strUser){
return USER_VOTES_HREF.replaceAll('#USERNAME',strUser).replace('#SHAKEN_TEXT',strData);
}
function formatWho(strName) {
return encloseATagUserVotes(strName, strName).replace("title", " class='username' title");
}
function columnDiv(header_neg, list_neg) {
return divNegativizators.replace('HEADER',header_neg).replace('LIST_NEG',list_neg);
}
function url_votes(page) {
return URL_VOTERS.replace('PAGE_COUNTER',page).replace('MENEO_ID', link_id);
}
function insertClassAvatar(nodeAvatar){
if (!nodeAvatar.src.includes('no-gravatar')) nodeAvatar.className = AVATAR_TOOLTIP_CLASS.replace('ID_USUARIO', extractUserIdFromAvatarURL(nodeAvatar.getAttribute('src')));
return nodeAvatar.outerHTML;
}
function extractUserIdFromAvatarURL(strURL) {
if (!strURL) return 0;
var lastPos = strURL.indexOf('-');
var firstPos = 0;
for (let i = lastPos; i >= 0; i--) {
if (strURL[i] === '/') { firstPos = i; break; }
}
return strURL.substring(firstPos+1,lastPos);
}