Skip to content

Instantly share code, notes, and snippets.

@josefandersson
Last active December 20, 2016 20:23
Show Gist options
  • Save josefandersson/87bb047bea31124ec7f6b4af2064bf71 to your computer and use it in GitHub Desktop.
Save josefandersson/87bb047bea31124ec7f6b4af2064bf71 to your computer and use it in GitHub Desktop.
A userscript for counting characters in a post! (In the same way the server counts characters in a post.)
// ==UserScript==
// @name HF Character Counter
// @description Counts the number of characters in a post or PM on Hackforums.net!
// @author Josef A. (DrDoof)
// @namespace https://github.com/josefandersson
// @require https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js
// @include *://hackforums.net/*
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @version 1.2.6
// @run-at document-end
// ==/UserScript==
/* HELLO USER - CHANGE THESE SETTINGS AS YOU WILL - ALL SHOULD BE SET TO TRUE FOR THE REAL CHARACTER COUNT (THE ONE USED FOR LUCKY AWARD) */
ignore = {
quotes: true, // Ignore quotes
images: true, // Ignore images
urls: true, // Ignore urls
emails: true, // Ignore emails
fonts: true, // Ignore fonts
colors: true, // Ignore colors
aligns: true, // Ignore aligns
sizes: true, // Ignore sizes
lists: true, // Ignore lists
italics: true, // Ignore italics
bolds: true, // Ignore bolds
underlines: true, // Ignore underlines
strikes: true, // Ignore strikes
spoilers: true, // Ignore spoilers
smilies: true, // Ignore smilies
codes: true, // Ignore codes
phps: true, // Ignore phps
videos: true, // Ignore videos
newlines: true, // Ignore newlines
};
/* END OF SETTINGS*/
// To get the real length of a textarea we have to think like the HF server!
sr = /^([ ]|\n|\t|\r)+/g;
er = /([ ]|\n|\t|\r)+$/g;
// The user may also toggle the counting of various things.
qr = /\[quote.*?\](.|\n)*?\[\/quote\]/g; // quotes
ir = /\[img\](http|https):\/\/.+\[\/img\]/g; // images
ur1 = /\[url\].+\[\/url\]/g; // 1st url variant
ur2 = /\[url=.+\]((?:.|\n)*?)\[\/url\]/g; // 2nd url variant
mr1 = /\[email\].+\[\/email\]/g; // 1st email variant
mr2 = /\[email=.+\]((?:.|\n)*?)\[\/email\]/g; // 2nd email variant
fr = /\[font=.+\]((?:.|\n)*?)\[\/font\]/g; // font
cr = /\[color=#[a-fA-F0-9]{6}\]((?:.|\n)*?)\[\/color\]/g; // color
ar = /\[align=(?:left|right|center|justify)\]((?:.|\n)*?)\[\/align\]/g; // align
sir = /\[size=(?:xx-small|x-small|small|medium|large|x-large|xx-large)\]((?:.|\n)*?)\[\/size\]/g; // size
lr = /\[list(?:=1|=a)?\]((?:.|\n)*?)\[\/list\]/g; // list
br = /\[b\]((?:.|\n)*?)\[\/b\]/g; // bold
itr = /\[i\]((?:.|\n)*?)\[\/i\]/g; // italic
ur = /\[u\]((?:.|\n)*?)\[\/u\]/g; // underline
str = /\[s\]((?:.|\n)*?)\[\/s\]/g; // strikethrough
cor = /\[code\]((?:.|\n)*?)\[\/code\]/g; // code
pr = /\[php\]((?:.|\n)*?)\[\/php\]/g; // php
vr = /\[video=(?:youtube|vimeo|yahoo)\]((?:.|\n)*?)\[\/video\]/g; // video (I believe only three of them works)
sr1 = /\[sp.*?\]((?:.|\n)*?)\[\/sp\]/g; // 1st spoiler variant
sr2 = /\[spoiler.*?\]((?:.|\n)*?)\[\/spoiler\]/g; // 2nd spoiler variant
smr = /:(pinch|victoire|hehe|oui|bebe-pleure|ohmy|blink|superman|nono|biggrin|sad|unsure|glare|roflmao|devlish|rolleyes|cool|gratte|confused|blackhat|ninja|blush|lipssealed|yeye|non|smile|whistle|sleep|evilgrin|omg|tongue|mad|huh|thumbsup|wacko|pirate):/g; // smilies
nr = /\n*/g; // newline
// Our textarea variable will just default to null.
ta = null;
// Whether or not we should ignore to filter ignore settings.
// If you are using longer posts this should probably be toggled to true to prevent lag.
// This gets toggled by clicking on the character counter text.
f = GM_getValue('f') === 'true';
/* Find the textarea for this page, add the counter
** element to it and add the eventlistener. */
(() => {
// Add the styling for the display text.
GM_addStyle([
'p#char_count {',
'margin-top: -20px;',
'float: right;',
'margin-right: 13px;',
'color: red;',
'opacity: 0.999', // This one has to be here but it makes absolutely no sense why... Stupid CSS.
'}'
].join(''));
// Determine the textarea from current path.
paths = {'/showthread.php': [25, 100], '/newreply.php': [25, 100], '/newthread.php': [25, false]};
if (paths[location.pathname]) {
ta = $('#message_new');
if (!ta.length) ta = $('#message');
low = paths[location.pathname][0];
high = paths[location.pathname][1];
}
// Whoops! No text areas on this page!
if (!ta) return;
// Add the element that displays the character count text after the text area.
(cc = $('<p>', { id: 'char_count', text: `${ta.text().length} characters`, onselectstart: 'return false;' })).insertAfter(ta);
// Update the character counter elements text and color.
u = () => {
if (high === false) {
cc.text(`${rl} characters`);
if (low <= rl) cc.css('color', 'green'); else cc.css('color', 'red');
} else {
if (f) {
cc.text(`${rl} characters (click to toggle lucky filtering)`);
if (low <= rl) cc.css('color', 'green'); else cc.css('color', 'red');
} else {
if (l == rl) cc.text(`${rl} characters`);
else cc.text(`${rl} characters (${l} lucky characters)`);
if (high <= l) cc.css('color', 'green'); else if (low <= rl) cc.css('color', '#008ae6'); else cc.css('color', 'red');
}
}
};
// Count the characters in the text right now.
lf = () => {
t = ta.val(), t = t.slice((t.match(sr) || [''])[0].length, -(t.match(er) || [''])[0].length || undefined); // Remove spaces at start and end of string and replace newlines with two underscores.
// This will be the character count before user filtering has been applied.
rl = t.split("\n").join('__').length;
// Don't filter ignore settings when f is true.
if (!f && high !== false) {
// Depending on the user settings we'll remove some things from the text.
if (ignore.newlines) t = t.replace(nr, '');
if (ignore.quotes) t = t.replace(qr, '');
if (ignore.images) t = t.replace(ir, '');
if (ignore.urls) { t = t.replace(ur1, ''); while (ur2.test(t)) t = t.replace(ur2, '$1'); }
if (ignore.emails) { t = t.replace(mr1, ''); while (mr2.test(t)) t = t.replace(mr2, '$1'); }
if (ignore.fonts) while (fr.test(t)) t = t.replace(fr, '$1');
if (ignore.colors) while (cr.test(t)) t = t.replace(cr, '$1');
if (ignore.aligns) while (ar.test(t)) t = t.replace(ar, '$1');
if (ignore.sizes) while (sir.test(t)) t = t.replace(sir, '$1');
if (ignore.lists) while (lr.test(t)) t = t.replace(lr, '$1');
if (ignore.italics) while (itr.test(t)) t = t.replace(itr, '$1');
if (ignore.bolds) while (br.test(t)) t = t.replace(br, '$1');
if (ignore.underlines) while (ur.test(t)) t = t.replace(ur, '$1');
if (ignore.strikes) while (str.test(t)) t = t.replace(str, '$1');
if (ignore.spoilers) { while (sr1.test(t)) t = t.replace(sr1, '$1'); while (sr2.test(t)) t = t.replace(sr2, '$1'); }
if (ignore.smilies) t = t.replace(smr, '');
if (ignore.codes) t = t.replace(cor, '');
if (ignore.phps) t = t.replace(pr, '');
if (ignore.videos) t = t.replace(vr, '');
// The length after filtering ignore settings.
l = t.length;
}
}
// Listen to every click event on the character counter element.
cc.click((e) => {
f = !f;
GM_setValue('f', `${f}`); // Save the state between pages.
lf();
u();
});
// Listen to every input event in the textarea and update the character counter element.
ta.on('input', (e) => {
// Count the characters in the text.
lf();
// Update the character counter elements text and color.
u();
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment