Shadow template v1 // Creates on the fly preview of different templates
New page
// Shadow template v1
// Creates on the fly preview of different templates
// ==/UserScript==
(function (window, mw, $) {
"use strict";
var templateNamespace = {};
var i18n = window.TemplateSandboxPreview || {
"en": {
"btn_exit": "Exit",
"input_templateplaceholder": "Enter template name",
"input_newtemplateplaceholder": "stub",
"label_previewTemplate": "Preview",
"label_templateName": "Enter template to replace",
"label_newtemplateName": "New template name",
"label_templateInvocation": "Template markup",
"label_replaceTemplate_links": "Replace whole transclusion",
"scriptName": "Shadow template"
}
};
var userLang = mw.config.get("wgUserLanguage") || "en";
var action = mw.config.get("wgAction");
// Gets and escapes messages
function msg(msgString) {
return mw.html.escape(i18n[userLang][msgString] || i18n.en[msgString] || "");
}
function createCmbBox(options) {
var Html = mw.html;
var cmbTextOptions = "";
options.forEach(function (item) {
cmbTextOptions += Html.element("option", {
"value": item
}, item);
});
return new Html.Raw(cmbTextOptions);
}
//Capitalizes string
function ucFirst(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
// Compares two titles
function compareTitle(title1, title2) {
try {
title1 = decodeURIComponent(title1);
title2 = decodeURIComponent(title2);
var tmpTitle1 = new mw.Title(title1);
var tmpTitle2 = new mw.Title(title2);
var isEqualNs = tmpTitle1.getNamespaceId() === tmpTitle2.getNamespaceId();
return ucFirst(tmpTitle1.getName()) === ucFirst(tmpTitle2.getName()) && isEqualNs;
} catch (e) {
console.log(title1, title2, e);
return false;
}
}
function createTemplateCombobox() {
var currentPage = mw.config.get("wgPageName");
var pageId;
var templateNames = [];
$.get("/api.php?action=query&titles=" + currentPage + "&prop=templates&format=json&indexpageids=true").then(function (templateData) {
pageId = templateData.query.pageids[0];
var templateDetails = templateData.query.pages[pageId];
if (templateDetails && templateDetails.templates) {
Object.keys(templateDetails.templates).forEach(function (id) {
if (id && templateDetails.templates[id].ns === 10) {
templateNames.push(templateDetails.templates[id].title);
}
});
}
$("#templateDropdown").html(createCmbBox(templateNames).value);
});
}
//https://github.com/spencermountain/wtf_wikipedia
//Finds template transclusions in text
function recursive_matches(opener, closer, text) {
var out = [];
var last = [];
var chars = text.split("");
var open = 0;
var characterIndex = 0;
var charGroup;
var extraChars = opener.length - 1;
var openerLocations = [];
var lastOpener = 0;
if (closer.length > 2) {
return;
}
while (characterIndex < chars.length) {
charGroup = chars[characterIndex];
if (extraChars > 0) {
charGroup = chars[characterIndex] + (chars[characterIndex + extraChars] || "");
}
//increment open tag
if (charGroup === opener) {
open += 1;
openerLocations.push(characterIndex);
if (extraChars > 0) {
last.push("{");
characterIndex += 1;
continue;
}
}
//decrement close tag
if (charGroup === closer) {
if (open > 0) {
//Internal search
lastOpener = openerLocations.pop();
out.push(text.substring(lastOpener, characterIndex + extraChars + 1));
}
open -= 1;
if (open < 0) {
open = 0;
}
}
if (open >= 0) {
last.push(chars[characterIndex]);
}
characterIndex += 1;
}
return out;
}
//Creates a form and adds current page name
function createForm() {
var Html = mw.html;
var output = "";
var formOutput = "";
var formContent = [{
tag: "label",
attribs: {},
content: msg("label_templateName")
}, {
tag: "select",
attribs: {
id: "templateDropdown",
style: "float:left;width: 150px;"
},
newline: true
}, {
tag: "input",
attribs: {
id: "templateName",
style: "float:right; width:150px",
type: "text",
placeholder: msg("input_templateplaceholder")
}
}, {
tag: "label",
attribs: {
"for": "newtemplateName"
},
content: msg("label_newtemplateName"),
newline: true
}, {
tag: "input",
attribs: {
id: "newTemplateName",
style: "float:right;width:150px",
type: "text",
placeholder: msg("input_newtemplateplaceholder")
}
}, {
tag: "label",
attribs: {
"for": "chkReplaceTemplateId"
},
content: msg("label_replaceTemplate_links"),
newline: true
}, {
tag: "input",
attribs: {
"id": "chkReplaceTemplateId",
type: "checkbox"
},
content: ""
}, {
tag: "label",
attribs: {
"for": "templateInvocationId",
style: "display:none",
id: "label_templateInvocation"
},
content: msg("label_templateInvocation"),
newline: true
}, {
tag: "textarea",
attribs: {
"id": "templateInvocationId",
style: "height: 5em; width: 100%;display:none",
placeholder: "{{template2|abc}}"
},
content: ""
}];
var formAttribs = {
"class": "WikiaForm"
};
var i;
for (i = 0; i < formContent.length; i += 1) {
if (formContent[i].newline) {
formOutput += "<br>";
}
formOutput += Html.element(formContent[i].tag, formContent[i].attribs, formContent[i].content);
}
output = Html.element("form", formAttribs, new Html.Raw(formOutput));
return output;
}
function replaceTemplate(template, newTemplateName, content, newContent) {
var invalidTitleChars = ["#", "<", ">", "[", "]", "|", "{", "}"];
var templateLinks = recursive_matches("{{", "}}", content);
if (templateLinks) {
var templateName = "";
var templateParts;
var tmpID;
var ns = "";
var templateContent;
var removableLinkList = [template];
var targetlinkId;
var targetLink;
for (tmpID = 0; tmpID < templateLinks.length; tmpID += 1) {
for (targetlinkId = 0; targetlinkId < removableLinkList.length; targetlinkId += 1) {
targetLink = removableLinkList[targetlinkId];
if (targetLink) {
templateParts = templateLinks[tmpID].split(":");
templateName = templateParts[0];
ns = templateParts[0].toLowerCase().substring(2);
if (templateNamespace[ns]) {
templateName = "{{" + templateParts[1];
}
templateName = templateName.substring(2, templateName.length - 2);
templateName = templateName.split("|")[0];
if (invalidTitleChars.indexOf(templateName.substring(0, 1)) < 0 &&
compareTitle("template:" + templateName, targetLink)) {
templateContent = templateLinks[tmpID];
if (!$("#chkReplaceTemplateId").prop("checked") && newTemplateName) {
content = content.replace("{{" + templateName, "{{" + newTemplateName);
console.log(content);
} else if ($("#chkReplaceTemplateId").prop("checked")) {
content = content.replace(templateContent, newContent);
}
}
}
}
}
}
return content;
}
function showTemplatePreview() {
var form = createForm();
createTemplateCombobox();
$.showCustomModal("Shadow template", form, {
id: "templateSandboxPreviewer",
width: 320,
buttons: [{
message: msg("btn_exit"),
id: "cancelButton",
handler: function () {
$("#templateSandboxPreviewer").closeModal();
}
}, {
message: msg("label_previewTemplate"),
id: "btnPreview",
defaultButton: true,
handler: function () {
var inputTemplateName = $("#templateName").val();
var inputTemplateData1 = $("#templateInvocationId").val();
var newTemplateName = $("#newTemplateName").val();
$.get(location.pathname + "?action=raw").then(function (content) {
var tmpNs = inputTemplateName.split(":")[0];
if (tmpNs.toLowerCase() !== "template") {
inputTemplateName += "template:";
}
var newContent = replaceTemplate(inputTemplateName, newTemplateName, content, inputTemplateData1);
if (newContent) {
(new mw.Api()).post({
action: "parse",
text: newContent,
title: mw.config.get("wgPageName")
}).done(function (data) {
if (data.error) {
return;
}
$("#mw-content-text").html(data.parse.text["*"]);
});
}
});
}
}]
});
$("#templateSandboxPreviewer").css({
top: "400px",
left: "85%",
position: "fixed"
});
$("#templateDropdown").on("click", function () {
$("#templateName").val($("#templateDropdown").val());
});
$("#chkReplaceTemplateId").on("click", function () {
$("#templateInvocationId").toggle();
$("#label_templateInvocation").toggle();
});
}
//Gets possible file namespaces
function setNamespaces() {
var namespaceIds = mw.config.get("wgNamespaceIds");
Object.keys(namespaceIds).forEach(function (name) {
if (namespaceIds[name] === 10) {
templateNamespace[name] = true;
}
});
}
function main() {
setNamespaces();
if (mw.config.get("skin") === "oasis" && $("#my-tools-menu").length && mw.config.get("wgNamespaceNumber") > -1 && action !== "edit") {
$("#my-tools-menu").prepend("<li class=\"custom\"><a style=\"cursor:pointer\" id=\"shadowTemplate\">" + msg("scriptName") + "</a></li>");
mw.util.addPortletLink("p-tb", "#", msg("scriptName"), "shadowTemplate");
}
$("a#shadowTemplate").on("click", function () {
showTemplatePreview();
});
}
main();
}(window, mw, $));