মিডিয়াউইকি:Gadget-CodeLinks.js

উইকিবই থেকে

লক্ষ্য করুন: প্রকাশ করার পর, পরিবর্তনগুলো দেখতে আপনাকে আপনার ব্রাউজারের ক্যাশে পরিষ্কার করার প্রয়োজন হতে পারে।

  • ফায়ারফক্স / সাফারি: পুনরায় লোড-এ ক্লিক করার সময় শিফট টিপে ধরে রাখুন, অথবা হয় Ctrl-F5 বা Ctrl-R টিপুন (ম্যাকে ⌘-R টিপুন)
  • গুগল ক্রোম: Ctrl-Shift-R (ম্যাকে ⌘-Shift-R) টিপুন
  • ইন্টারনেট এক্সপ্লোরার / এজ: Ctrl ধরে রাখা অবস্থায় Refresh-এ ক্লিক করুন, অথবা Ctrl-F5 টিপুন
  • অপেরা: Ctrl-F5 টিপুন।
/*jshint undef:true, latedef:true */
/*global mw, jQuery */

jQuery(function CodeLinksIIFE() {
'use strict';

// by John Gruber, from https://daringfireball.net/2010/07/improved_regex_for_matching_urls
var URLRegExp = /\b((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/i;

function processComment(node) {
	var wikilinkMatch, templateMatch, URLMatch,
		textNode = node.firstChild; // always a text node.
	
	while (
		(wikilinkMatch = /\[\[([^|{}\[\]\n]+)?(?:\|.*?)?]]/.exec(textNode.data))
		|| (templateMatch = /(\{\{(?:#invoke:)?)([^|{}\[\]\n#]+)(?=\||}})/i.exec(textNode.data))
		|| (URLMatch = URLRegExp.exec(textNode.data))
	) {
		var link = document.createElement('a'),
			start = (wikilinkMatch || templateMatch || URLMatch).index,
			linkText;
		link.classList.add("code-link");
		
		if (URLMatch) {
			var URL = URLMatch[0];
			link.href = URL;
			linkText = URL;
		} else {
			var fullPageName;
			if (wikilinkMatch) {
				linkText = wikilinkMatch[0];
				fullPageName = wikilinkMatch[1];
			} else if (templateMatch) {
				var prefix = templateMatch[1],
					pageName = templateMatch[2];
				linkText = pageName;
				fullPageName = (prefix === '{{#invoke:' ? 'Module:' : 'Template:')
					+ pageName;
				link.title = fullPageName;
				start += prefix.length;
			}
			link.href = mw.util.getUrl(fullPageName);
		}
		
		var beforeLink = textNode.data.substring(0, start),
			afterLink = textNode.data.substring(start + linkText.length);
		
		textNode.data = afterLink;
		link.appendChild(document.createTextNode(linkText));
		node.insertBefore(link, textNode);
		node.insertBefore(document.createTextNode(beforeLink), link);
		
		// ensure all matches are null at beginning of loop body; is this necessary?
		wikilinkMatch = templateMatch = URLMatch = null;
	}
}

function each(coll, walk) {
	return Array.prototype.forEach.call(coll, walk);
}

var commentClasses = [ 'c', 'c1', 'cm' ];
each(document.getElementsByClassName('mw-highlight'), function (codeBlock) {
	each(commentClasses, function (commentClass) {
		each(codeBlock.getElementsByClassName(commentClass), processComment);
	});
});

// Link module names after `require` and `mw.loadData`, and tracking template
// names after `require("Module:debug").track`.
var copyArray = Array.from ? Array.from.bind(Array) :
	function copyArray(array) {
		return Array.prototype.slice.call(array);
	};

var classes = {
	identifier: "n", functionName: "nb",
	singleQuoteString: "s1", doubleQuoteString: "s2",
};

var trackingTemplateElements = [], moduleNames = [], dataModuleNames = [];

var functionNames = document.getElementsByClassName(classes.functionName);

Array.prototype.forEach.call(functionNames, function (functionName) {
	var text = functionName.firstChild.nodeValue;
	if (text !== "require")
		return;
	
	var next = functionName.nextElementSibling;
	var nextText = next && next.firstChild && next.firstChild.nodeValue;
	
	var hasParenthesis = nextText === "(";
	if (hasParenthesis) {
		next = next.nextElementSibling;
		nextText = next && next.firstChild && next.firstChild.nodeValue;
	}
	
	var classList = next.classList;
	if (!(classList.contains(classes.singleQuoteString)
	|| classList.contains(classes.doubleQuoteString)))
		return;
	
	var string = next;
	var stringValue = nextText;
	if (!stringValue)
		return;
	
	next = next.nextElementSibling;
	nextText = next && next.firstChild && next.firstChild.nodeValue;
	if (hasParenthesis && nextText && nextText[0] !== ")")
		return;
	
	moduleNames.push(string);
	
	if (hasParenthesis ? nextText === ")." : nextText === "."
	&& (/^["']mod(?:ule)?:(.+)["']$/i.exec(stringValue) || [])[1] === "debug") {
		next = next.nextElementSibling;
		nextText = next && next.firstChild && next.firstChild.nodeValue;
		if (nextText !== "track")
			return;
		
		next = next.nextElementSibling;
		if (!next) return;
		nextText = next && next.firstChild && next.firstChild.nodeValue;
		var trackWithParenthesis = false;
		if (nextText === "(") {
			next = next.nextElementSibling;
			trackWithParenthesis = true;
		}
		
		classList = next.classList;
		if (!(classList.contains(classes.singleQuoteString)
		|| classList.contains(classes.doubleQuoteString)))
			return;
		
		nextText = next && next.firstChild && next.firstChild.nodeValue;
		if (!nextText)
			return;
		
		// If there was a parenthesis on one side – `track("...")` rather than
		// `track "..."` – make sure there's a matching parenthesis on the other side.
		if (trackWithParenthesis) {
			var after = next.nextElementSibling;
			var afterText = after && after.firstChild && after.firstChild.nodeValue;
			if (afterText !== ")")
				return;
		}
		
		trackingTemplateElements.push(next);
	}
});

var strings = copyArray(document.getElementsByClassName(classes.singleQuoteString))
	.concat(copyArray(document.getElementsByClassName(classes.doubleQuoteString)));

Array.prototype.forEach.call(strings, function (string) {
	if (moduleNames.indexOf(string) !== -1 || trackingTemplateElements.indexOf(string) !== -1)
		return;
	
	var stringValue = string.firstChild.nodeValue;
	if (!/^["'](?:module|mod):/i.test(stringValue))
		return;
	
	var prev = string.previousElementSibling;
	var prevText = prev && prev.firstChild && prev.firstChild.nodeValue;
	if (prevText === "(") {
		var next = string.nextElementSibling;
		var nextText = next && next.firstChild && next.firstChild.nodeValue;
		if (!(nextText && nextText[0] === ")"))
			return;
		
		prev = prev.previousElementSibling;
		prevText = prev && prev.firstChild && prev.firstChild.nodeValue;
	}
	
	if (prevText !== "loadData")
		return;
	
	prev = prev.previousElementSibling;
	prevText = prev && prev.firstChild && prev.firstChild.nodeValue;
	if (prevText !== ".")
		return;
	
	prev = prev.previousElementSibling;
	prevText = prev && prev.firstChild && prev.firstChild.nodeValue;
	if (prevText !== "mw")
		return;
	
	dataModuleNames.push(string);
});

if (moduleNames.length > 0 || trackingTemplateElements.length > 0
|| dataModuleNames.length > 0) {
	mw.loader.using("mediawiki.util").done(function () {
		function addLink(element, page) {
			if (!(element instanceof Element))
				throw new TypeError("Expected Element object");
			var link = document.createElement("a");
			link.href = mw.util.getUrl(page);
			// put text node from element inside link
			var firstChild = element.firstChild;
			if (!(firstChild instanceof Text))
				throw new TypeError("Expected Text object");
			link.appendChild(firstChild);
			element.appendChild(link); // put link inside syntax-highlighted string
		}
		
		// Link module names to module pages, or to the section in the Scribunto
		// manual.
		moduleNames.concat(dataModuleNames).forEach(function (module) {
			var link = document.createElement("a");
			var stringValue = module.firstChild.nodeValue;
			var moduleName = stringValue.substring(1, stringValue.length - 1);
			var linkPage = /^mod(?:ule)?:/i.test(moduleName)
				? moduleName
				: "mw:Extension:Scribunto/Lua reference manual#" + moduleName;
			addLink(module, linkPage);
		});
		
		// Link tracking templates to [[Special:WhatLinksHere]].
		trackingTemplateElements.forEach(function (trackingTemplate) {
			var text = trackingTemplate.firstChild && trackingTemplate.firstChild.nodeValue;
			if (!text)
				return;
			var trackingCode = text.substring(1, text.length - 1);
			
			addLink(trackingTemplate, "Special:WhatLinksHere/Template:tracking/" + trackingCode);
		});
	});
}

});