// ==UserScript==
// @name TorViet Shoutbox Enhancer
// @namespace http://torviet.com/userdetails.php?id=1662
// @version 0.9
// @license http://www.wtfpl.net/txt/copying/
// @homepageURL https://github.com/S-a-l-a-d/TorViet-Shoutbox-Enhancer
// @supportURL https://github.com/S-a-l-a-d/TorViet-Shoutbox-Enhancer/issues
// @icon http://torviet.com/pic/salad.png
// @description A small script to tweak the shoutbox
// @author Salad
// @match http://torviet.com/qa.php*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_addStyle
// ==/UserScript==
(function() {
// First let's get the elements which we will work on.
var allWrapper = document.getElementById("all-wrapper"),
boxHead = document.getElementById("boxHead"),
marquee = document.getElementById("marquee"),
sltTheme = document.getElementById("sltTheme"),
boxQuestion = document.getElementById("boxQuestion"),
clock = document.getElementById("clock"),
idQuestion = document.getElementById("idQuestion"),
emoGroup = document.getElementById("emo-group"),
emoGroupDetail = document.getElementById("emo-group-detail");
// Also create a namespace.
var EMOTICON = (function() {
var emoList = GM_getValue("emoList"),
emoListHtml = GM_getValue("emoListHtml") || "",
emoHtml = "";
var promptForEmoList = function(action, list) {
var message = "Chọn bộ emoticon bạn muốn" + " " + action + ":\n",
answer;
for (var i = 0, len = list.length; i < len; i++) {
message += i + 1 + ". " + list[i] + "\n";
}
message += "Điền tên bộ emoticon, ngăn cách bằng dấu phẩy, phân biệt hoa/thường." + " " +
"Có thể điền emoticon đơn bằng cách điền tên tập tin emoticon đó.\nVí dụ: Voz,707,Rage";
do {
answer = prompt(message);
}
while (!answer || answer.trim() === "");
return answer.replace(/\s{2,}/g, " ").trim().split(",");
};
var initemoList = function() {
var emoListAvailable = [];
for (var i = 0, options = emoGroup.options, len = options.length; i < len; i++) {
emoListAvailable.push(options[i].text);
}
emoList = promptForEmoList("sử dụng", emoListAvailable);
GM_setValue("emoList", emoList);
};
var requestEmoticons = function(groupName) {
var request = new XMLHttpRequest();
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Using synchronous request here is the simplest implementation to make it work. *
* This process is fast enough so the user will hardly notice the unresponsive moment *
* while the browser is sending the request and receiving the response. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
request.open("POST", "qa_smiley_ajax.php", false);
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.onreadystatechange = function() {
request.readyState == 4 && request.status == 200 &&
(emoHtml = JSON.parse(request.responseText).str);
};
request.send("group=" + groupName);
};
var makeEmoticonHtml = function(emoName) {
emoHtml = "<div style=\"height:43px;width:43px;float:left;display:inline-block;margin:0 0 1px 1px;\">" +
"<img style=\"max-width: 43px; max-height: 43px; cursor: pointer;\" src=\"/pic/smilies/" + emoName +
".gif\" alt=\"[em" + emoName + "]\"></div>";
};
return {
checkemoList: function() {
!emoList && initemoList();
},
add: function() {
var emoListAvailable = [];
for (var i = 0, options = emoGroup.options, len = options.length; i < len; i++) {
(emoList.indexOf(options[i].text) === -1) &&
emoListAvailable.push(options[i].text);
}
var emoListToAdd = promptForEmoList("thêm", emoListAvailable);
for (var i = 0, len = emoListToAdd.length; i < len; i++) {
(emoList.indexOf(emoListToAdd[i]) === -1) &&
emoList.push(emoListToAdd[i]);
}
GM_setValue("emoList", emoList);
GM_deleteValue("emoListHtml");
location.href = "qa.php";
},
remove: function() {
var emoListToRemove = promptForEmoList("xóa", emoList);
for (var i = 0, len = emoListToRemove.length; i < len; i++) {
var index = emoList.indexOf(emoListToRemove[i]);
(index > -1) && emoList.splice(index, 1);
}
GM_setValue("emoList", emoList);
GM_deleteValue("emoListHtml");
location.href = "qa.php";
},
clear: function() {
GM_deleteValue("emoList");
GM_deleteValue("emoListHtml");
location.href = "qa.php";
},
getEmoticons: function(groupName) {
requestEmoticons(groupName);
return emoHtml;
},
generateEmoticons: function(emoName) {
makeEmoticonHtml(emoName);
return emoHtml;
},
addEmosToEmoGroup: function() {
emoGroupDetail.innerHTML = "";
if (emoListHtml === "") {
for (var i = 0, len = emoList.length; i < len; i++) {
emoListHtml += isNaN(emoList[i]) ?
this.getEmoticons(emoList[i]) :
this.generateEmoticons(emoList[i]);
}
GM_setValue("emoListHtml", emoListHtml);
}
emoGroupDetail.innerHTML = emoListHtml;
},
addEmoGroupEvent: function() {
// Let's add click events for the newly added emoticons.
for (var i = 0, emos = emoGroupDetail.childNodes, len = emos.length; i < len; i++)
emos[i].firstChild.addEventListener("click", function(e) {
idQuestion.value += e.target.parentNode.getAttribute("alt");
idQuestion.focus();
});
}
};
})();
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Now remove the unnecessary elements including the box containing new torrents *
* and football news, the warning, the theme drop-down list and the clock. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
allWrapper.className = "";
boxHead.parentNode.removeChild(boxHead);
marquee.parentNode.removeChild(marquee);
sltTheme.parentNode.removeChild(sltTheme);
while (clock.lastChild) {
clock.removeChild(clock.lastChild);
}
// And polish things with our custom CSS.
var specialCase = typeof InstallTrigger !== "undefined" ?
"#wrapper-below {" +
" height: calc(100% - 67px);" +
"}" +
"#emo-section {" +
" height: calc(100% - 74px);" +
"}" :
"#wrapper-below {" +
" height: calc(100% - 62px);" +
"}" +
"#emo-section {" +
" height: calc(100% - 69px);" +
"}";
GM_addStyle(
".slimScrollDiv, #emo-group-detail {" +
" height: 100% !important;" +
"}" +
specialCase
);
var toBeAppendedToClock = document.createDocumentFragment(),
someText = document.createElement("span"),
btnAdd = document.createElement("input"),
btnRemove = document.createElement("input"),
btnClear = document.createElement("input");
someText.innerHTML = "For custom emoticon group<br />";
btnAdd.type = "button";
btnAdd.value = "Add";
btnAdd.addEventListener("click", EMOTICON.add);
btnRemove.type = "button";
btnRemove.value = "Remove";
btnRemove.addEventListener("click", EMOTICON.remove);
btnClear.type = "button";
btnClear.value = "Clear";
btnClear.addEventListener("click", EMOTICON.clear);
toBeAppendedToClock.appendChild(emoGroup.parentNode);
toBeAppendedToClock.appendChild(someText);
toBeAppendedToClock.appendChild(btnAdd);
toBeAppendedToClock.appendChild(btnRemove);
toBeAppendedToClock.appendChild(btnClear);
clock.appendChild(toBeAppendedToClock);
var btnOnline = document.createElement("input");
btnOnline.type = "button";
btnOnline.value = "Online";
btnOnline.addEventListener("click", function() {
$.post("qaload.php", "Action=rq", function(data) {
$("#boxQA").find("ul").prepend($(data.ou).fadeIn("slow"));
});
});
document.getElementById("input-section-a").appendChild(btnOnline);
// Here comes our own functions.
function changeEmoGroup() {
emoGroupDetail.innerHTML = EMOTICON.getEmoticons(emoGroup.value);
// EMOTICON.addEmoGroupEvent();
}
function keyEvent(e) {
switch (e.keyCode) {
// Down arrow.
case 40:
emoGroup !== document.activeElement &&
emoGroup.selectedIndex !== emoGroup.length - 1 &&
emoGroup.selectedIndex++;
changeEmoGroup();
break;
// Up arrow.
case 38:
emoGroup !== document.activeElement &&
emoGroup.selectedIndex !== 0 &&
emoGroup.selectedIndex--;
console.log(emoGroup.value);
changeEmoGroup();
break;
// Enter.
case 13:
var inputText = idQuestion.value;
inputText = inputText.replace(/(:\^\))|(\/:\))/g, "[em528]");
inputText = inputText.replace(/:\)/g, "[em564]");
inputText = inputText.replace(/:\({2}/g, "[em7]");
inputText = inputText.replace(/:\(/g, "[em561]");
inputText = inputText.replace(/:x/g, "[em535]");
inputText = inputText.replace(/:"\>/g, "[em23]");
inputText = inputText.replace(/:\-?\*/g, "[em570]");
inputText = inputText.replace(/=\(\(/g, "[em572]");
inputText = inputText.replace(/:\-?[oO]/g, "[em222]");
inputText = inputText.replace(/[xX]\-?\(/g, "[em541]");
inputText = inputText.replace(/[bB]\-\)/g, "[em555]");
inputText = inputText.replace(/\>:\)/g, "[em552]");
inputText = inputText.replace(/\(:\|/g, "[em571]");
inputText = inputText.replace(/:\|/g, "[em206]");
inputText = inputText.replace(/:\-&/g, "[em37]");
inputText = inputText.replace(/:\-?\?/g, "[em223]");
inputText = inputText.replace(/=\)\)/g, "[em707]");
inputText = inputText.replace(/:\-?[dD]/g, "[em536]");
inputText = inputText.replace(/;;\)/g, "[em524]");
inputText = inputText.replace(/:\-?\>/g, "[em537]");
inputText = inputText.replace(/:\-[sS]/g, "[em558]");
inputText = inputText.replace(/\[\-\(/g, "[em200]");
inputText = inputText.replace(/=[pP]~/g, "[em566]");
inputText = inputText.replace(/;\)\)/g, "[em18]");
inputText = inputText.replace(/[tT]_[tT]/g, "[em544]");
inputText = inputText.replace(/\-_\-/g, "[em136]");
inputText = inputText.replace(/\(finger\)/g, "[em720]");
idQuestion.value = inputText;
break;
default:
}
}
function arrayIsNumeric(arr) {
return arr.every(element => !isNaN(element));
}
function decimalArrayToString(messageArray) {
return String.fromCharCode.apply(null, messageArray);
}
function messageIsUrl(message) {
return /^(http)/.test(message);
}
function formatMessage(message) {
return "<a class=\"faqlink\" href=\"" + message + "\" target=\"_blank\">" +
(message.length > 80 ?
(message.substr(0, 20) + "..." +
message.substring(message.length - 30, message.length) + "</a>") : message);
}
function decodeMessages() {
$(".Q1, .Q1-right").find("span").not(".nowrap, .time").each(function () {
var message = $(this).html();
if (!arrayIsNumeric(message.split(" "))) {
return true;
}
message = decimalArrayToString(message.split(" "));
$(this).html(messageIsUrl(message) ? formatMessage(message) : message);
});
}
function observeMessages() {
var observer = new MutationObserver(function (mutations, observer) {
var nodes = mutations[0].addedNodes[0].getElementsByTagName("span"),
targetNode = nodes[nodes.length -1],
parentNodeClassName = targetNode && targetNode.parentNode.className,
message = targetNode && targetNode.innerHTML;
if (parentNodeClassName === "Q1" || parentNodeClassName === "Q1-right") {
if (!arrayIsNumeric(message.split(" "))) {
return false;
}
message = decimalArrayToString(message.split(" "));
if (messageIsUrl(message)) {
targetNode.innerHTML = formatMessage(message);
} else {
targetNode.innerHTML = message;
}
}
});
observer.observe(boxQuestion, {
childList: true,
subtree : true
});
}
// The following should run at startup.
document.addEventListener("keydown", keyEvent);
decodeMessages();
observeMessages();
EMOTICON.checkemoList();
EMOTICON.addEmosToEmoGroup();
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Let's see if the user is using Firefox. *
* This method is taken from http://stackoverflow.com/questions/9847580/ *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// typeof InstallTrigger === "undefined" && EMOTICON.addEmoGroupEvent();
idQuestion.focus();
})();