User:Chlod/Scripts/WordCount.js

Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// This entire script was shamelessly copied from [[User:GoldenRing/wordcount.js]].
// This function shamelessly copied from https://stackoverflow.com/a/11348383/274460
(function () {
	$.fn.ignore = function(sel) {
		return this.clone().find(sel || "> *").remove().end();
	};
	
	function countWords(h, s) {
		$(h).each(function(i, match) {
			var elements = $(match).nextUntil(s || h);
			
			// Ignore hidden elements
			elements.find(':hidden').addClass('wordcount-ignore');
			// Ignore striked comments
			elements.find('*').filter(function() { return $(this).css('text-decoration').match(/line-through/); }).addClass('wordcount-ignore');
			// Ignore site components
			elements.find('div#siteSub').addClass('wordcount-ignore');
			elements.find('div#contentSub').addClass('wordcount-ignore');
			elements.find('div#jump-to-nav').addClass('wordcount-ignore');
			// Find elements that aren't ignored
			elements = elements.not('.wordcount-ignore');
			// Get the text
			var text = elements.ignore('.localcomments').ignore('.wordcount-ignore').text();
			// Remove all timestamps
			var search = /(\d{1,2}):(\d{2}), (\d{1,2}) ([A-Z][a-z]+) (\d{4}) \(UTC\)/g;
			text = text.replace(search, '');
	
			text = text
				// Split words by whitespace (will keep hyphenations as one word)
				.split(/\s+/)
				// Filter by strings worth more than one non-whitespace symbol
				.filter(function(d) { return d.length > 0; })
				// Filter by letters
	            .filter(function(d) {
	            	try {
	            		// Try unicode matching (if browser supports)
	            		const letterRegex = new RegExp("\\p{Letter}", "u");
	            		return d.match(letterRegex); 
	            	} catch (e) {
	            		// Fall back to normalization and letter filtering
						if (d.normalize != null) {
							// Normalize words that are worth one Unicode codepoint into two
							d = d.normalize("NFD");
						}
							
						// Match all letter characters (won't pick up on Kana or accented Latin letters)
						return d.match(/\w/);
	            	}
	            });
				// Filter by letters (ES5-compatible)
			var count = text.length;
			$(match).append($('<span class="wordcount mw-editsection">' + count.toLocaleString() + ' words</span>'));
		});
	}
	
	function run() {
		$(".wordcount").remove();
		countWords('.mw-parser-output h1', 'h1');
		countWords('.mw-parser-output h2', 'h1, h2');
		countWords('.mw-parser-output h3', 'h1, h2, h3');
	}
	
	mw.hook("wikipage.content").add(() => {
		// Immediately run on start for WP:ARC
		if (mw.config.get("wgPageName").indexOf("Wikipedia:Arbitration/Requests/Case") === 0) {
			run();
		}
	});
	
	mw.util.addPortletLink(
	    "p-cactions",
	    "javascript:void(0)",
	    "Word count",
	    "ca-wordcount"
	).addEventListener("click", run);
})();