MediaWiki:Gadget-Prosesize.js

This is an old revision of this page, as edited by Galobtter (talk | contribs) at 05:29, 13 August 2019 (fix). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
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.
/*jshint maxerr:999*/
//copy of [[User:Dr_pda/prosesize.js]]
//TODO: modernize (User:Shubinator/DYKcheck.js may have useful code? or use xtools api ) and fix to work on all maintained skins propose to become gadget
//Wikipedia:Village_pump_(technical)/Archive_161#"Page_size"_Tool:_"Word_count"_script_'User:Dr_pda/prosesize.js'_does_not_work_with_skin_=_Timeless
//<nowiki>
//This function adds a link to the toolbox which, when clicked, displays the size of the page
//and the size of the prose. See the talk page for more details.
//
//To use this function add {{subst:js|User:Dr pda/prosesize.js}} to your monobook.js
//
function loadXMLDocPassingTemplate(url, handler, page) {
	// branch for native XMLHttpRequest object
	if (window.XMLHttpRequest) {
		var req = new XMLHttpRequest();
	}
	// branch for IE/Windows ActiveX version
	else if (window.ActiveXObject) {
		var req = new ActiveXObject("Microsoft.XMLHTTP");
	}
	if (req) {
		req.onreadystatechange = function() {
			handler(req, page)
		};
		req.open("GET", url, true);
		req.send("");
	}
}

function getWikiText(req, page) {
	// only if req shows "loaded"
	if (req.readyState == 4) {
		// only if "OK"
		if (req.status == 200) {
			// ...processing statements go here...
			response = req.responseXML.documentElement;
			var rev = response.getElementsByTagName('rev');
			if (rev.length > 0) {
				result = rev[0].getAttribute('size');
				if (result > 10240) {
					result = (result / 1024).toFixed(0) + '&nbsp;kB';
				} else {
					result = result + '&nbsp;B';
				}
				wiki_value = document.createElement("li");
				wiki_value.id = "wiki-size";
				wiki_value.innerHTML = '<b>Wiki text: </b>' + result;
				var output = document.getElementById("document-size-stats");
				prose_value = document.getElementById("prose-size");
				output.insertBefore(wiki_value, prose_value);
			} else {
				//alert("There was a problem using the Wikipedia Search to find the wiki text size\nEither the search is not working or the correct article did not appear on the first page of results");
				wiki_value = document.createElement("li");
				wiki_value.id = "wiki-size";
				wiki_value.innerHTML = '<b>Wiki text: </b>Problem getting wiki text size';
				var output = document.getElementById("document-size-stats");
				prose_value = document.getElementById("prose-size");
				output.insertBefore(wiki_value, prose_value);
			}
		} else {
			alert("There was a problem retrieving the XML data:\n" +
				req.statusText);
		}
	}
}

function getFileSize(req, page) {
	// only if req shows "loaded"
	if (req.readyState == 4) {
		// only if "OK"
		if (req.status == 200) {
			// ...processing statements go here...
			var fsize = req.responseText.length;
			window.status = fsize;
			var total_value = document.createElement("li");
			total_value.id = "total-size";
			total_value.innerHTML = '<b>File size: </b>' + (fsize / 1024).toFixed(0) + '&nbsp;kB';
			var output = document.getElementById("document-size-stats");
			var prose_html_value = document.getElementById("prose-size-html");
			output.insertBefore(total_value, prose_html_value);
		} else {
			alert("There was a problem retrieving the XML data:\n" +
				req.statusText + "\n(" + url + ")");
		}
	}
}

function getLength(id) {
	var textLength = 0;
	for (var i = 0; i < id.childNodes.length; i++) {
		if (id.childNodes[i].nodeType === Node.TEXT_NODE) {
			textLength += id.childNodes[i].nodeValue.length;
		} else if (id.childNodes[i].nodeType === Node.ELEMENT_NODE &&
			(id.childNodes[i].id == 'coordinates' || id.childNodes[i].className.indexOf('emplate') != -1)) {
			//special case for {{coord}} and {{fact}}-like templates
			//Exclude from length, and don't set background yellow
			id.childNodes[i].style.cssText = 'background-color:white';
		} else {
			textLength += getLength(id.childNodes[i]);
		}
	}
	return textLength;
}

function getRefMarkLength(id, html) {
	var textLength = 0;
	for (var i = 0; i < id.childNodes.length; i++) {
		if (id.childNodes[i].nodeType === Node.ELEMENT_NODE && id.childNodes[i].className == 'reference') {
			textLength += (html) ? id.childNodes[i].innerHTML.length : getLength(id.childNodes[i]);
		}
	}
	return textLength;
}

function getDocumentSize() {
	var bodyContent;
	if ($.inArray(mw.config.get('skin'), ['vector', 'monobook']) !== -1) {
		bodyContent = $('#mw-content-text .mw-parser-output');
	}
	//Same for all skins if previewing page
	if (mw.config.get('wgAction') == 'submit') {
		bodyContent = $('#wikiPreview .mw-parser-output');
	}

	if (bodyContent.length === 0) {
		return;
	}
	bodyContent = bodyContent[0];

	if (document.getElementById("document-size-stats")) {
		//if statistics already exist, turn them off and remove highlighting
		var output = document.getElementById("document-size-stats");
		var oldStyle = output.className;
		var pList = bodyContent.getElementsByTagName("p");
		for (var i = 0; i < pList.length; i++) {
			if (pList[i].parentNode == bodyContent) {
				pList[i].style.cssText = oldStyle;
			}
		}
		output.parentNode.removeChild(output);
		var header = document.getElementById("document-size-header");
		header.parentNode.removeChild(header);
	} else {
		var output = document.createElement("ul");
		output.id = "document-size-stats";

		var prose_html_value = document.createElement("li");
		prose_html_value.id = "prose-size-html";
		output.appendChild(prose_html_value);

		var ref_html_value = document.createElement("li");
		ref_html_value.id = "ref-size-html";
		output.appendChild(ref_html_value);

		var prose_value = document.createElement("li");
		prose_value.id = "prose-size";
		output.appendChild(prose_value);
		output.className = bodyContent.getElementsByTagName("p").item(0).style.cssText;

		var ref_value = document.createElement("li");
		ref_value.id = "ref-size";
		output.appendChild(ref_value);

		bodyContent.insertBefore(output, bodyContent.firstChild);

		var header = document.createElement("span");
		header.id = "document-size-header";
		header.innerHTML = '<br/>Document statistics: <small><i>(See <a href="//en.wikipedia.org/wiki/User_talk:Dr_pda/prosesize.js">here</a> for details.)<i></small>';
		bodyContent.insertBefore(header, output);

		//File size not well defined for preview mode or section edit
		if (mw.config.get('wgAction') != 'submit') {
			loadXMLDocPassingTemplate(___location.pathname, getFileSize, '');
		}

		//Get size of images only if browser supports filesize property (IE)
		var iList = bodyContent.getElementsByTagName("img");
		if (iList.length > 0 && iList[0].fileSize) {
			//Get size of images included in document
			var image_size = 0;
			var first_magnify = true;

			for (var i = 0; i < iList.length; i++) {
				var im = iList[i];
				if (im.getAttribute("src").indexOf("magnify-clip.png") != -1) {
					if (first_magnify) {
						image_size += im.fileSize * 1;
						first_magnify = false;
					}
				} else {
					image_size += im.fileSize * 1;
				}
			}
			var image_value = document.createElement("li");
			image_value.id = "image-size";
			image_value.innerHTML = '<b>Images: </b>' + (image_size / 1024).toFixed(0) + '&nbsp;kB';
			output.appendChild(image_value);

		}
		//Calculate prose size and size of reference markers ([1] etc)
		var pList = bodyContent.getElementsByTagName("p");

		prose_size = 0;
		prose_size_html = 0;
		refmark_size = 0;
		refmark_size_html = 0;
		word_count = 0;
		for (var i = 0; i < pList.length; i++) {
			var para = pList[i];
			if (para.parentNode == bodyContent) {
				prose_size += getLength(para);
				prose_size_html += para.innerHTML.length;
				refmark_size += getRefMarkLength(para, false);
				refmark_size_html += getRefMarkLength(para, true);
				word_count += para.innerHTML.replace(/(<([^>]+)>)/ig, "").split(' ').length;
				para.style.cssText = "background-color:yellow";
			}
		}

		if ((prose_size - refmark_size) > 10240) {
			prose_value.innerHTML = '<b>Prose size (text only): </b>' + ((prose_size - refmark_size) / 1024).toFixed(0) + '&nbsp;kB (' + word_count + ' words) "readable prose size"';
		} else {
			prose_value.innerHTML = '<b>Prose size (text only): </b>' + (prose_size - refmark_size) + '&nbsp;B (' + word_count + ' words) "readable prose size"';
		}

		if ((prose_size_html - refmark_size_html) > 10240) {
			prose_html_value.innerHTML = '<b>Prose size (including all HTML code): </b>' + ((prose_size_html - refmark_size_html) / 1024).toFixed(0) + '&nbsp;kB';
		} else {
			prose_html_value.innerHTML = '<b>Prose size (including all HTML code): </b>' + (prose_size_html - refmark_size_html) + '&nbsp;B';
		}

		//Calculate size of references (i.e. output of <references/>)
		var rList = bodyContent.getElementsByTagName("ol");
		var ref_size = 0;
		var ref_size_html = 0;
		for (var i = 0; i < rList.length; i++) {
			if (rList[i].parentNode.className == "references") {
				ref_size = getLength(rList[i]);
				ref_size_html = rList[i].innerHTML.length;
			}
		}

		if ((ref_size + refmark_size) > 10240) {
			ref_value.innerHTML = '<b>References (text only): </b>' + ((ref_size + refmark_size) / 1024).toFixed(0) + '&nbsp;kB';
		} else {
			ref_value.innerHTML = '<b>References (text only): </b>' + (ref_size + refmark_size) + '&nbsp;B';
		}

		if ((ref_size_html + refmark_size_html) > 10240) {
			ref_html_value.innerHTML = '<b>References (including all HTML code): </b>' + ((ref_size_html + refmark_size_html) / 1024).toFixed(0) + '&nbsp;kB';
		} else {
			ref_html_value.innerHTML = '<b>References (including all HTML code): </b>' + (ref_size_html + refmark_size_html) + '&nbsp;B';
		}

		//get correct name of article from wikipedia-defined global variables
		var pageNameUnderscores = mw.config.get('wgPageName');
		var pageNameSpaces = pageNameUnderscores.replace(/_/g, ' ');

		//if page is a permalink, diff, etc don't try to search
		if (!___location.pathname.match('/w/index.php')) {
			//Get revision size from API
			var searchURL = mw.config.get('wgScriptPath') + '/api.php?action=query&prop=revisions&rvprop=size&format=xml&revids=' + mw.config.get('wgCurRevisionId');
			loadXMLDocPassingTemplate(searchURL, getWikiText, pageNameSpaces);
		} else if (mw.config.get('wgAction') == 'submit') {
			//Get size of text in edit box
			result = document.getElementById('wpTextbox1').value.length;
			if (result > 10240) {
				result = (result / 1024).toFixed(0) + '&nbsp;kB';
			} else {
				result = result + '&nbsp;B';
			}
			wiki_value = document.createElement("li");
			wiki_value.id = "wiki-size";
			wiki_value.innerHTML = '<b>Wiki text: </b>' + result;
			var output = document.getElementById("document-size-stats");
			prose_value = document.getElementById("prose-size");
			output.insertBefore(wiki_value, prose_value);
		}
	}
}

$.when($.ready, mw.loader.using( 'mediawiki.util' )).then( function() {
	// Depending on whether in edit mode or preview/view mode, show the approppiate response upon clicking the portlet link
	var func;
	if (mw.config.get('wgAction') == 'edit' || (mw.config.get('wgAction') == 'submit' && document.getElementById('wikiDiff'))) {
		func = function() {
			alert("You need to preview the text for the prose size script to work in edit mode.");
		};
		mw.util.addCSS( '#t-page-size:first-child { color:black;}');	
	} else if (['view', 'submit', 'historysubmit', 'purge'].indexOf(mw.config.get('wgAction')) !== -1) {
		func = function() {
			getDocumentSize();
		};
	}
	if (func) {
		$(mw.util.addPortletLink('p-tb', '#', 'Page size', 't-page-size', 'Calculate page and prose size')).on( 'click', function(e) {
			e.preventDefault();
			func();
		});
	}
});

//</nowiki>