// ==UserScript==
// @name MiaouDTC - DansTonChat.com
// @name:fr MiaouDTC - DansTonChat.com
// @namespace jlgrall_UserScripts
// @version 1.2
// @description Improves browsing of quotes and comments on DansTonChat.com (also known as DTC). Miaou... Miaou... MiaouDTC
// @description:fr Améliore la navigation des quotes et des commentaires sur DansTonChat.com (DTC pour les intimes). Miaou... Miaou... MiaouDTC
// @homepage https://greasyfork.org/en/scripts/369900-miaoudtc-danstonchat-com
// @supportURL https://greasyfork.org/en/scripts/369900-miaoudtc-danstonchat-com/feedback
// @contributionURL https://www.tipeee.com/danstonchat
// @author jlgrall
// @license MIT License
// @match https://danstonchat.com/*
// @exclude https://danstonchat.com/user/login*
// @exclude https://danstonchat.com/myaccount*
// @grant none
// ==/UserScript==
(function($) {
'use strict';
var $empty = $();
var Miaou = window.Miaou = {
// CSS rules:
styleContent: [
// GENERAL:
'div.cls-cookie { display: none; }',
// scoreRatio:
'span.miaouScoreRatio { float: left; margin-left: -20px; }',
// miaouComments Header:
'.miaouComments-header { float: left; background: #ddd; }',
'.miaouComments-header:hover { background: #ccc; }',
'.miaouComments-header > span,',
'.miaouComments-header > a { padding: 11px 10px 12px; font-size: 1.1em; _font-weight: bold; display: inline-block; color: #222; }',
'@media (max-width: 530px) {',
' .miaouComments-header > a { text-indent: -9999px; line-height: 0; }', // Idea from: https://stackoverflow.com/questions/7896402/how-can-i-replace-text-with-css/22054588#22054588
' .miaouComments-header > a:after { content: "Comms"; text-indent: 0; line-height: initial; display: block; }',
'}',
'@media (max-width: 350px) {',
' .miaouComments-header > a { padding: 5px; }',
' .miaouComments-header > a:after { content: "C"; font-size: 1.4em; }',
'}',
// miaouComments Wrapper and Body:
'.miaouComments-wrapper { border-left: 10px solid #ddd; border-bottom: 10px solid #ddd; padding-left: 6px; }',
'.miaouComments-body { max-height: 500px; overflow: auto; resize: vertical; padding-top: 6px; }',
'@media (max-height: 660px) { .miaouComments-body { max-height: 74vh; } }',
'@media (max-height: 570px) { .miaouComments-body { max-height: 68vh; } }',
'@media (max-height: 480px) { .miaouComments-body { max-height: 60vh; } }',
'.miaouItem.miaouComments-hide .miaouComments-wrapper { display: none; }',
// Linkified quotes:
'.item-content a.miaou-linkifiedQuoteRef { display: unset; max-width: unset; color: #8cbd6a; }',
'.item-content a.miaou-linkifiedQuoteRef:hover { color: #add095; }',
],
// Comments loading states:
COMMENTS_UNLOADED: 0,
COMMENTS_LOADING: 1,
COMMENTS_LOADED: 2,
COMMENTS_ERROR: 3,
getCommentsStateForItem: function($item) {
var state = $item.data('data-miaou-commentsState');
return state === undefined ? Miaou.COMMENTS_UNLOADED : state;
},
setCommentsStateForItem: function($item, state) {
$item.data('data-miaou-commentsState', state);
},
itemsById: {},
extractItemId: function($item) { // itemId is always a string (it should not be converted to a number)
var item = $item[0];
for (var i = 0; i < item.classList.length; i++) {
var name = item.classList.item(i);
if (name !== 'item') {
var match = name.match(/^item(\d{1,9})$/);
if (match) return match[1];
}
}
return undefined;
},
initItem: function($item) {
var itemId = Miaou.extractItemId($item);
var itemURL = $item.find('div.item-content > a').attr('href');
var $score = $item.find('span.score');
var scoreMatch = $score.text().match(/(\d{1,6})\s*\/\s*(\d{1,6})/);
var scoreRatio = scoreMatch ? (scoreMatch[1] / scoreMatch[2]).toFixed(1) : NaN;
var nbComments = parseInt($item.find('span.comments').text(), 10);
Miaou.itemsById[itemId] = (Miaou.itemsById[itemId] || $empty).add($item);
var $scoreRatio = $('<span class="miaouScoreRatio"> = ' + scoreRatio + '</span>');
$item.data({
'miaou-itemId': itemId,
'miaou-itemURL': itemURL,
'miaou-nbComments': nbComments,
'miaou-$scoreRatio': $scoreRatio,
});
$item.addClass('miaouItem miaouItem' + itemId);
$scoreRatio.insertAfter($score);
if ($item.closest('.items, .item-listing').length > 0) Miaou._initItemComments($item);
return $item;
},
_initItemComments: function($item) {
var $commentsHeader = $('<div class="miaouComments-header"></div>');
var $commentsWrapper = $('<div class="miaouComments-wrapper"></div>');
var $commentsBody = $('<div class="miaouComments-body"></div>');
$item.data({
'miaou-$commentsHeader': $commentsHeader,
'miaou-$commentsWrapper': $commentsWrapper,
'miaou-$commentsBody': $commentsBody,
});
$item.addClass('miaouComments-hide'); // TODO: use 'miaouComments-show' instead ?
$commentsHeader.insertBefore($item.find('.meta-bar .vote-plus'));
$commentsWrapper.append($commentsBody).appendTo($item);
Miaou.updateCommentsUI($item, Miaou.COMMENTS_UNLOADED);
return $item;
},
updateCommentsUI: function($item, state) {
if (state === undefined) {
state = Miaou.getCommentsStateForItem($item);
}
else {
Miaou.setCommentsStateForItem($item, state);
}
var itemId = $item.data('miaou-itemId');
var nbComments = $item.data('miaou-nbComments');
var $commentsHeader = $item.data('miaou-$commentsHeader');
switch(state) {
case Miaou.COMMENTS_UNLOADED:
var hrefUnloaded = 'javascript:Miaou.loadCommentsForItemId(\'' + itemId + '\')';
$commentsHeader.html('<a href="' + hrefUnloaded + '">Afficher les commentaires (' + nbComments + ')</a>');
break;
case Miaou.COMMENTS_LOADING:
$commentsHeader.html('<span>Chargement des commentaires...</span>');
break;
case Miaou.COMMENTS_LOADED:
var hidden = $item.hasClass('miaouComments-hide');
if (hidden) {
var hrefLoadedHidden = 'javascript:Miaou.showCommentsForItemId(\'' + itemId + '\')';
$commentsHeader.html('<a href="' + hrefLoadedHidden + '">Afficher les commentaires (' + nbComments + ')</a>');
}
else {
var hrefLoadedShown = 'javascript:Miaou.hideCommentsForItemId(\'' + itemId + '\')';
$commentsHeader.html('<a href="' + hrefLoadedShown + '">Masquer les commentaires (' + nbComments + ')</a>');
}
break;
case Miaou.COMMENTS_ERROR:
var hrefError = 'javascript:Miaou.loadCommentsForItemId(\'' + itemId + '\')';
$commentsHeader.html('<a href="' + hrefError + '">Recharger les commentaires</a>');
break;
}
return $item;
},
loadCommentsForItemId: function(itemId) {
var $items = Miaou.itemsById[itemId] || $empty;
if ($items.length === 0) return console.error('Could not find element item with id: ' + itemId);
var itemURL = undefined;
$items.each(function(i, item) {
var $item = $(item);
if (Miaou.getCommentsStateForItem($item) === Miaou.COMMENTS_LOADING) return;
Miaou.updateCommentsUI($item, Miaou.COMMENTS_LOADING);
itemURL = $item.data('miaou-itemURL');
});
if (!itemURL) return; // Probably already loading.
$.get(itemURL, 'html').then(function(data) {
var $comments = $($.parseHTML(data)).find('.comment-list').remove('script, style, link');
if ($comments.length > 0) {
var nbComments = $comments.find('.comment').length;
return {$comments: Miaou.linkifyQuoteRefs($comments), state: Miaou.COMMENTS_LOADED, nbComments: nbComments};
}
else {
$comments = $.parse('<div class="comment-list">Erreur: commentaires non trouvés.</div>');
return $.Deffered().rejectWith(data, {$comments: $comments, state: Miaou.COMMENTS_ERROR});
}
}, function(jqXHR) {
var $comments = $.parse('<div class="comment-list">Erreur: status = "' + jqXHR.statusText + '"</div>');
return {$comments: $comments, state: Miaou.COMMENTS_ERROR};
}).always(function(data) {
// In case content of page was modified during xhr:
var $items = Miaou.itemsById[itemId] || $empty;
if ($items.length === 0) return;
$items.each(function(i, item) {
var $item = $(item);
if ('nbComments' in data) $item.data('miaou-nbComments', data.nbComments);
var $commentsBody = $item.data('miaou-$commentsBody');
$commentsBody.empty().append(data.$comments);
Miaou.updateCommentsUI($item, data.state);
Miaou.showCommentsForItemId(itemId);
});
});
},
showCommentsForItemId: function(itemId) {
var $items = Miaou.itemsById[itemId] || $empty;
$items.each(function(i, item) {
var $item = $(item);
var state = Miaou.getCommentsStateForItem($item);
if (state === Miaou.COMMENTS_UNLOADED) Miaou.loadCommentsForItemId(itemId);
$item.removeClass('miaouComments-hide');
Miaou.updateCommentsUI($item);
});
},
hideCommentsForItemId: function(itemId) {
var $items = Miaou.itemsById[itemId] || $empty;
$items.each(function(i, item) {
var $item = $(item);
$item.addClass('miaouComments-hide');
Miaou.updateCommentsUI($item);
});
},
toggleCommentsForItemId: function(itemId) {
var $items = Miaou.itemsById[itemId] || $empty;
if ($items.filter(':not(.miaouComments-hide)').length > 0) {
Miaou.hideCommentsForItemId(itemId);
}
else {
Miaou.showCommentsForItemId(itemId);
}
},
showCommentsForAllItems: function() {
for (var itemId in Miaou.itemsById) Miaou.showCommentsForItemId(itemId);
},
hideCommentsForAllItems: function() {
for (var itemId in Miaou.itemsById) Miaou.hideCommentsForItemId(itemId);
},
toggleCommentsForAllItems: function() {
for (var itemId in Miaou.itemsById) Miaou.toggleCommentsForItemId(itemId);
},
linkifyQuoteRefs: function(node) {
if (node.each) { // node is a jQuery object
node.each(function(i, node) {
Miaou.linkifyQuoteRefs(node);
});
}
else if (node.hasChildNodes()) {
for (var i = 0; i < node.childNodes.length; i++){
Miaou.linkifyQuoteRefs(node.childNodes[i]);
}
}
else if (node.nodeType === Node.TEXT_NODE
&& node.textContent.indexOf('#') > -1 // Quick test speeds up the process.
&& !node.parentNode.classList.contains('miaou-linkifiedQuoteRef')) {
// Regex to find a DTC quote reference: a '#' followed by up to 9 digits,
// and the reference must be separated from other words.
var newHTML = node.textContent.replace(/\B#(\d{1,9})\b/g, '<a href="/$1.html" class="miaou-linkifiedQuoteRef">$&</a>');
$(node).replaceWith(newHTML);
}
return node;
},
};
// MAIN:
Miaou.pageHasItemsList = document.querySelector('div.items, div.item-listing') !== null;
Miaou.$style = $('<style/>', {html: Miaou.styleContent.join('\n'), 'id': 'Miaou.$style'}).appendTo(document.head);
$('.item').each(function(i, item) {
Miaou.initItem($(item));
});
//Miaou.allowActionLoadAll = true;
if (Miaou.pageHasItemsList && Miaou.allowActionLoadAll) {
var $showAllComments = $('<a href="javascript:Miaou.showCommentsForAllItems()" class="miaouShowAllComments"><span>Afficher tous les commentaires</span></a>');
$showAllComments.insertAfter('div.contenu a.submit.android');
var $hideAllComments = $('<a href="javascript:Miaou.hideCommentsForAllItems()" class="miaouHideAllComments"><span>Masquer tous les commentaires</span></a>');
$hideAllComments.insertAfter($showAllComments);
}
Miaou.linkifyQuoteRefs($('.item-content, .comment-content'));
})(window.jQuery);