Skip to content

Instantly share code, notes, and snippets.

@AmauryCarrade
Last active January 14, 2017 17:23
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 AmauryCarrade/27a5266d49a3c1406e0e to your computer and use it in GitHub Desktop.
Save AmauryCarrade/27a5266d49a3c1406e0e to your computer and use it in GitHub Desktop.
Affichage de raccourcis de modération et divers autres améliorations sur le forum de ZCraft
// ==UserScript==
// @name Affichage de raccourcis de modération sur ZCraft
// @namespace eu.carrade.amaury.zcraft
// @description Affichage de raccourcis de modération sur ZCraft
// @include https://forum.zcraft.fr/viewtopic.php*
// @include https://forum.zcraft.fr/post.php*
// @include https://forum.zcraft.fr/edit.php*
// @include http://forum.zcraft.fr/viewtopic.php*
// @include http://forum.zcraft.fr/post.php*
// @include http://forum.zcraft.fr/edit.php*
// @updateURL https://gist.githubusercontent.com/AmauryCarrade/27a5266d49a3c1406e0e/raw/mod-zcraft.user.js
// @version 4
// @grant none
// ==/UserScript==
/**
* Adds a CSS rule.
*
* @param selector (string) The CSS selector.
* @param rules (string) The CSS rules, written in natural CSS.
*/
function addCSSRule(selector, rules)
{
var style = document.styleSheets[2];
if(style.cssRules)
style.insertRule(selector + "{ " + rules + " }", 0);
else if(style.rules)
style.addRule(selector, rules);
}
/**
* Returns an XMLHttpRequest object.
*/
function getXHR()
{
if(window.XMLHttpRequest)
return new XMLHttpRequest();
else
return new ActiveXObject("Microsoft.XMLHTTP");
}
/**
* Returns the DOM of a distant page through a callback.
*
* @param url (string) The URL to be loaded.
* @param callback (runnable) A callback called with these arguments:
* - dom (Document) → the loaded DOM (null in case of fail)
* - success (bool) → true if the request was answered by a 200 status code
* - xhr (XMLHttpRequest) → The XMLHttpRequest object.
* @param method The HTTP method ("POST", "GET", ...).
*
* @return The XMLHttpRequest object.
*/
function getDistantDOM(url, callback, method)
{
var xhr = getXHR();
xhr.responseType = 'document';
xhr.onload = function()
{
callback(xhr.response, xhr.status == 200, xhr);
}
xhr.open(method == undefined ? "GET" : method, url, true);
xhr.send();
return xhr;
}
// Better smiley size
addCSSRule(".smiley", "max-width: 18px !important; max-height: 18px !important;");
// Applications helpers injections
addCSSRule(".zus_fake_link", "color: #2365B0; cursor: pointer;");
addCSSRule(".zus_textarea_bottom", "font-size: 0.8em;");
addCSSRule(".zus_bottom_title", "font-weight: bold; padding-right: 15px;");
addCSSRule(".zus_error", "color: #FE1616;");
var text_separator = "  •  ";
var textareas_helpers = "<div class='zus_textarea_bottom'><span class='zus_bottom_title'>Candidatures</span> ";
textareas_helpers += "<span class='zus_fake_link' id='zus_accept'>Insérer le texte d'acceptation</span>" + text_separator;
textareas_helpers += "<span class='zus_fake_link' id='zus_tag'>Ajouter un tag</span>";
textareas_helpers += "</div>"
var textareas = document.getElementsByTagName("textarea");
for(var i = 0; i < textareas.length; i++)
{
var textarea = textareas.item(i);
if(textarea.getAttribute("name") == "req_message")
{
// We are here in a message textarea.
textarea.insertAdjacentHTML("afterend", textareas_helpers);
}
}
var texts = {};
texts["accepted"] = "Tu es accepté parmi les Zcraftiens : félicitations ! :)\n\nPense bien à (re)lire le [url=http://www.zcraft.fr/zcraft-mode-demploi/guide-de-survie/]guide de survie pour les nouveaux Zcraftiens[/url] qui contient une mine d'informations pour bien démarrer.";
document.getElementById("zus_accept").onclick = function()
{
insertTag(texts["accepted"], "");
}
// Tags management
var tag_link = document.getElementById("zus_tag");
var tag_adding = false;
tag_link.onclick = function()
{
if(tag_adding) return false;
var tag = prompt("Quel tag ajouter ?\nSi présent, le tag sera retiré.\n\n", "Accepté");
if(tag == null || tag == "")
return false;
tag_adding = true;
tag_link.innerHTML = "Ajout en cours...";
var root = location.origin + "/";
var formtype = ""; // "fast" (form under the topic), "post" (dedicated page for a new post) or "edit" (edit page).
switch(location.pathname)
{
case "/viewtopic.php":
formtype = "fast";
break;
case "/post.php":
formtype = "post";
break;
case "/edit.php":
formtype = "edit";
break;
}
/*
1/ Get the title, by loading the first page and parsing the page's title.
2/ Compute the new title (addition of the tag at the beginning).
3/ Update the title, in the database (AJAX request) and visually (page title, breadcumbs, main title).
*/
/* 1 - What is the topic ID? */
var topicID = undefined;
// Edit & new message pages
if(formtype == "edit" || formtype == "post") // The topic ID is in the breadcumbs, there's a link to the first page.
{
var breadcrumbs = document.getElementById("brdmain").getElementsByClassName("crumbs").item(0).getElementsByTagName("li");
for(var i = 0; i < breadcrumbs.length; i++)
{
var linkHref = breadcrumbs.item(i).getElementsByTagName("a").item(0).getAttribute("href");
if(linkHref != "" && linkHref.substr(0, 13) == "viewtopic.php")
{
topicID = Number(linkHref.split("?")[1].split("=")[1]);
break;
}
}
}
else if(formtype == "fast") // The topic ID is in the RSS feed link: extern.php?action=feed&amp;tid=<TopicID>&amp;type=rss
{
var links = document.getElementsByTagName("link");
for(var i = 0; i < links.length; i++)
{
var link = links.item(i);
var linkHref = link.getAttribute("href");
if(link.getAttribute("rel") == "alternate" && link.getAttribute("type") == "application/rss+xml" && linkHref.substr(0, 27) == "extern.php?action=feed&tid=")
{
topicID = Number(linkHref.split("?")[1].split("&")[1].split("=")[1]);
}
}
}
if(topicID == undefined || topicID <= 0)
{
console.error("[Tag] ERROR: unable to add the tag. Cannot retrieve the topic ID (found: " + topicID + ") at " + location.href);
endTagAddition(false);
return;
}
/* 2 - What is the message ID? And the title? */
var firstPageURL = root + "viewtopic.php?id=" + topicID;
getDistantDOM(firstPageURL, function(firstDOM, success)
{
if(!success)
{
console.error("[Tag] ERROR: unable to load the first topic page (topic ID: " + topicID + ") at " + location.href);
endTagAddition(false);
return;
}
var firstPostID = Number(firstDOM.getElementById("brdmain").getElementsByClassName("firstpost").item(0).getAttribute("id").substring(1));
var postTitle = firstDOM.getElementsByTagName("title")[0].textContent.split("/")[0].trim();
postTitle = postTitle.substr(0, postTitle.length - (" (Page 1)".length));
/* 3 - Final title? */
var fullTag = "[" + tag + "] ";
if(postTitle.indexOf(fullTag) == -1)
postTitle = fullTag + postTitle;
else
postTitle = postTitle.substring(fullTag.length);
/* 4 - Database-side update */
var editFirstMessageFormURL = root + "edit.php?id=" + firstPostID + "&action=edit";
getDistantDOM(editFirstMessageFormURL, function(editFirstDOM, success)
{
if(!success)
{
console.error("[Tag] ERROR: unable to load the first topic page (topic ID: " + topicID + ") at " + location.href + ". Are you allowed to do that?");
endTagAddition(false);
return;
}
//var form_sent = "1";
var req_subject = postTitle;
var req_message = "";
//var silent = "1";
//var submit = "Valider";
var editForm = editFirstDOM.getElementById("edit");
if(editForm == null) // Unauthorized. The HTTP response code is 200 even when the user is not allowed to edit a message >< .
{
console.error("[Tag] ERROR: unable to load the first topic page (topic ID: " + topicID + ") at " + location.href + ". Access denied!");
endTagAddition(false);
return;
}
var textareas = editForm.getElementsByTagName("textarea");
for(var i = 0; i < textareas.length; i++)
{
var firstPostTextarea = textareas.item(i);
if(firstPostTextarea.getAttribute("name") == "req_message")
{
req_message = firstPostTextarea.innerHTML;
}
}
var xhr = getXHR();
var postParams = "";
postParams += "form_sent=1"
postParams += "&req_subject=" + encodeURIComponent(req_subject);
postParams += "&req_message=" + encodeURIComponent(req_message);
postParams += "&silent=1";
postParams += "&submit=Valider"
xhr.open("POST", editFirstMessageFormURL, true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.setRequestHeader("Content-length", postParams.length);
xhr.setRequestHeader("Referer", editFirstMessageFormURL); // needed: without the request is rejected.
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.setRequestHeader('X-Alt-Referer', editFirstMessageFormURL);
xhr.setRequestHeader("Connection", "close");
xhr.onreadystatechange = function()
{
if(xhr.readyState == 4)
{
if(xhr.status == 200)
{
endTagAddition(true);
console.log(xhr.responseText);
}
else
{
console.error("[Tag] ERROR: unable to save the new title at " + location.href + ". The server responded: " + xhr.status);
console.error(xhr);
endTagAddition(false);
return;
}
}
}
xhr.send(postParams);
});
});
}
/**
* Ends the tag addition display by setting the link text to a message (related to the success), and a few seconds later, putting back the original text.
*
* @param success (bool) Used to determine what will be displayed.
*/
function endTagAddition(success)
{
var message = success ? "Tag ajouté avec succès" : "Impossible d'ajouter le tag ! Consultez la console pour les détails."
tag_link.innerHTML = message;
if(!success) tag_link.classList.add("zus_error");
setTimeout(function() {
tag_link.innerHTML = "Ajouter un tag";
if(!success) tag_link.classList.remove("zus_error");
tag_adding = false;
}, 4000);
}
// « New messages » link on every topic
// (TODO link detection to add it only if needed, and this on all pages?)
document.getElementById("searchlinks").insertAdjacentHTML("afterbegin", "<dd><span><a href='search.php?action=show_new'>Afficher les nouveaux messages</a></span></dd>");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment