User:L10nM4st3r/wEditor.js
Appearance
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
if (location.href.includes("&diff=")){
mw.loader.load('//en.wikipedia.org/w/index.php?title=User:Cacycle/wikEdDiff.js&action=raw&ctype=text/javascript');
}
var wikEdDiffConfig = {};
wikEdDiffConfig.clipLinesRightMax = 4;
wikEdDiffConfig.clipLinesLeftMax = 2;
var wEditData = {
// Is the user creating a new page
is_new_page: false,
// Is viewing source code, cannot edit
is_viewing_source: false,
// Used for showing changes
old_text: "",
// The section the user is editing. Will be -1 if editing the entire page.
edit_section: -1,
// Required for the undo/redo to work properly
undoIndex: 0,
undo_hisory: [],
undo_hisory_cursor: [],
lastUndoType: "",
undoRedoCooldown: false,
}
const TEXT_VALUES = {
previewText: "Show Preview",
previewTooltip: "Preview your changes",
changesText: "Show Changes",
changesTooltip: "Show which changes you made to the text",
saveEditText: "Save Changes",
saveEditTooltip: "Save your changes",
savePageText: "Save",
savePageTooltip: "Save this page",
editSummaryPlaceholder: "Edit Summary",
editSummaryCreatePlaceholder: "Summary",
editSummaryTooltip: "Enter a short summary",
minorEditLabel: "Minor Edit",
watchPageLabel: "Watch This Page",
editSummaryClearTooltip: "Clear summary",
insertWikilinkTooltip: "Insert Wiki-link Brackets",
insertTemplateTooltip: "Insert Template Brackets",
undoTooltip: "Undo",
redoTooltip: "Redo",
}
{
function wEditBox_contentOnKeyPress(e){
if (wEditData.undoRedoCooldown) return;
var textarea = document.getElementById("wedit-content");
var thisUndoType = "key";
var isNullInput = e.key === "Shift" || e.key === "Control" || e.key === "Alt" || e.key === "Meta" || e.ctrlKey || e.altKey;
if (e.shiftKey && e.ctrlKey && e.key === 'Z') wEditBox_redo();
else if (!e.shiftKey && e.ctrlKey && e.key === 'z') wEditBox_undo();
else if (e.ctrlKey && e.key === 'y') wEditBox_redo();
// Disable the default undo-redo
if (e.ctrlKey && (e.key === 'z' || e.key === 'y')) {
e.preventDefault();
return;
}
if (e.key === 'Enter')
thisUndoType = "newline";
else if (e.key === 'Backspace' || e.key === 'Delete')
thisUndoType = "backspace";
else if (e.key === ' ')
thisUndoType = "space";
else if ([";", "!", "\"", "£", "$", "%", "^", "&", "*", "(", ")", "_", "-", "+", "=", "[", "]", "{", "}", ":", "@", "'", "#", "~", "?", "/", ">", "<", ".", ",", "|", "\\", "`", "¬", "¦"].includes(e.key))
thisUndoType = e.key;
else if (e.ctrlKey && e.key === 'v') {
isNullInput = false;
thisUndoType = "paste" + Math.random().toString()
}
else if (e.ctrlKey && e.key === 'x') {
isNullInput = false;
thisUndoType = "cut" + Math.random().toString();
}
// Press tab to crreate an indent
else if (e.key === 'Tab'){
wEditBox_insertText("\t");
thisUndoType = "indent";
e.preventDefault();
}
if (wEditData.undoIndex+1 < wEditData.undo_hisory.length && !isNullInput) {
wEditData.undo_hisory.length = wEditData.undoIndex + 1;
wEditData.undo_hisory_cursor.length = wEditData.undoIndex + 1;
}
if (wEditData.undo_hisory_cursor.length === 0)
wEditData.undo_hisory_cursor.push(textarea.selectionStart);
if (thisUndoType !== wEditData.lastUndoType && !isNullInput) {
wEditData.lastUndoType = thisUndoType;
wEditData.undoIndex += 1;
wEditData.undo_hisory.push("");
wEditData.undo_hisory_cursor.push(textarea.selectionStart);
}
if (!isNullInput) {
wEditData.undoRedoCooldown = true;
setTimeout(() => {
wEditData.undoRedoCooldown = false;
wEditData.undo_hisory[wEditData.undo_hisory.length-1] = textarea.value;
wEditData.undo_hisory_cursor[wEditData.undo_hisory.length-1] = textarea.selectionStart;
}, 1);
}
document.getElementById("wedit-undo").disabled = !wEditData.undoIndex > 0;
document.getElementById("wedit-redo").disabled = wEditData.undoIndex+1 >= wEditData.undo_hisory.length;
}
// Load the editor UI
if (mw.config.get("wgAction") === "edit" || mw.config.get("wgAction") === "submit") {
// Load the diff.js library.
mw.loader.load("https://en.wikipedia.org/w/index.php?title=User:Cacycle/diff.js&action=raw&ctype=text/javascript");
var pageName = replaceAll(mw.config.get("wgPageName").toLowerCase(), " ", "_");
var pageTitle = document.getElementsByClassName("mw-first-heading")[0].innerText;
if (pageTitle.toLowerCase().startsWith("view source for " + pageName))
wEditData.is_viewing_source = true;
if (replaceAll(pageTitle.toLowerCase(), " ", "_") === "creating_" + pageName)
wEditData.is_new_page = true;
if (location.href.includes("§ion=")) {
var href = location.href;
href = href.slice(href.indexOf("§ion=") + 9, href.length);
// Make sure to strip additional arguments, such as "summary="
if (href.includes("&")) href.slice(0, href.indexOf("&"));
wEditData.edit_section = Number(href);
}
if (!wEditData.is_viewing_source) {
var editTextBoxValue = document.getElementById("wpTextbox1").value;
wEditData.undo_hisory.push(editTextBoxValue);
var editSummaryValue = document.getElementsByName('wpSummary')[0].value;
wEditData.old_text = editTextBoxValue;
var topDiv = document.createElement("div");
var editform = document.getElementById("editform");
editform.style.display = "none";
var container = document.createElement("div");
container.innerHTML = generateEditor();
editform.parentNode.insertBefore(container, editform.nextNode);
document.getElementById("wedit-content").value = editTextBoxValue;
document.getElementById("wedit-content").addEventListener("keydown", wEditBox_contentOnKeyPress);
document.getElementById("wedit-summary").value = editSummaryValue;
document.getElementById("wedit-summary").addEventListener("keydown", wEditBox_summaryOnKeyPress);
}
}
function generateEditor() {
var header = '<style>.unselectable {-webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none;} .checkbox {margin-left: 10px; margin-right: 7px} </style>';
var textbox = '<textarea onclick="wEditData.lastUndoType=\'\'" id="wedit-content" style="width:100%; max-height:250em; min-height:10em; height: 25em; resize:vertical; overflow:auto"></textarea>';
var output = header + '<div style="background-color:#cbdaf2">' + generateToolBar() + textbox + generateSubmitBar() + '</div><div style="min-height:160px" id="wedit-previewContent"></div>';
return output;
}
function generateToolBar() {
var category1 = `
<input type="button" id="wedit-undo" disabled="true" style="background: url(https://upload.wikimedia.org/wikipedia/commons/thumb/5/5e/Undo_Inkscape_Icon.svg/16px-Undo_Inkscape_Icon.svg.png?20201113140121); background-size: 100% 100%; cursor:pointer; width: 32px; height:32px" onclick="wEditBox_undo()" title="${TEXT_VALUES.undoTooltip}"></input>
<input type="button" id="wedit-redo" disabled="true" style="background: url(https://upload.wikimedia.org/wikipedia/commons/thumb/7/74/Redo_Inkscape_Icon.svg/16px-Redo_Inkscape_Icon.svg.png?20201113143731); background-size: 100% 100%; cursor:pointer; width: 32px; height:32px" onclick="wEditBox_redo()" title="${TEXT_VALUES.redoTooltip}"></input>`;
var category1Box = '<div style="padding: 5px 5px 5px 5px; margin: 7px 7px 7px 7px; border: 1px black solid; flex:1">' + category1 + '</div>';
var category2 = `
<input style="background: url(https://upload.wikimedia.org/wikipedia/commons/d/d6/WikiText.svg); background-size: 100% 100%; cursor:pointer; display:inline; width:32px; height:32px" title="${TEXT_VALUES.insertWikilinkTooltip}" type="button" onclick="wEditBox_insertWikiLink()"></input>
<input style="background: url(https://upload.wikimedia.org/wikipedia/commons/a/ab/CurlyBracketsBlue.svg); background-size: 100% 100%; cursor:pointer; display:inline; width:32px; height:32px" title="${TEXT_VALUES.insertTemplateTooltip}" type="button" onclick="wEditBox_insertTemplateBrackets()"></input>`;
var category2Box = '<div style="padding: 5px 5px 5px 5px; margin: 7px 7px 7px 7px; border: 1px black solid; flex:1">' + category2 + '</div>';
var output = '<div style="background-color:#cbdaf2; display:flex">' + category1Box + category2Box + '</div>';
return output;
}
function generateSubmitBar() {
if (wEditData.is_viewing_source) return "";
var editSummaryInput = '<input style="flex:1" id="wedit-summary" title="' + TEXT_VALUES.editSummaryTooltip + '" placeholder="' + (wEditData.is_new_page ? TEXT_VALUES.editSummaryCreatePlaceholder : TEXT_VALUES.editSummaryPlaceholder) + '" type="text" maxlength="400"></input>';
var editSummaryClear = '<input style="cursor:pointer; display:inline; width:2em" id="wedit-summary-clear" title="' + TEXT_VALUES.editSummaryClearTooltip + '" type="button" value="X" onclick="document.getElementById(\'wedit-summary\').value=\'\'; document.getElementById(\'wedit-summary\').focus();"></input>';
var minorEdit = wEditData.is_new_page ? "" : '<label class="unselectable" for="wedit-minor"><input id="wedit-minor" name="wedit-minor"' + (document.getElementById("wpMinoredit").checked ? " checked=true" : "") + ' class="checkbox" type="checkbox"></input>' + TEXT_VALUES.minorEditLabel + '</label>';
var watchPageToggle = '<label class="unselectable" for="wedit-watch"><input id="wedit-watch" name="wedit-watch"' + (document.getElementById("wpWatchthis").checked ? " checked=true" : "") + ' class="checkbox" type="checkbox"></input>' + TEXT_VALUES.watchPageLabel + '</label>';
var saveEdit = '<input style="cursor:pointer; background: linear-gradient(0.99turn, #6daafc, #ebeef2); display:inline; flex:1; height: 2em" id="wedit-save-edit" title="' + (wEditData.is_new_page ? TEXT_VALUES.savePageTooltip : TEXT_VALUES.saveEditTooltip) + '" type="button" value="' + (wEditData.is_new_page ? TEXT_VALUES.savePageText : TEXT_VALUES.saveEditText) + '" onclick="wEditBox_saveEdit();"></input>';
var previewPage = '<input style="cursor:pointer; display:inline; flex:1; height: 2em" id="wedit-show-preview" title="' + TEXT_VALUES.previewTooltip + '" type="button" value="' + TEXT_VALUES.previewText + '" onclick="wEditBox_showPreview();"></input>';
var viewChanges = wEditData.is_new_page ? "" : '<input style="cursor:pointer; display:inline; flex:1; height: 2em" id="wedit-show-showChanges" title="' + TEXT_VALUES.changesTooltip + '" type="button" value="' + TEXT_VALUES.changesText + '" onclick="wEditBox_showChanges();"></input>';
var editSummaryBar = '<div style="display:flex; margin: 6px 3px 6px 3px;">' + editSummaryClear + editSummaryInput + '</div>';
var saveButtonsBar = '<div style="display:flex; margin: 6px 3px 6px 3px;">' + saveEdit + previewPage + viewChanges + '</div>';
return editSummaryBar + minorEdit + watchPageToggle + saveButtonsBar;
}
}
function wEditBox_showChanges() {
var wikEdDiff = new WikEdDiff();
document.getElementById('wedit-previewContent').innerHTML = wikEdDiff.diff( wEditData.old_text, document.getElementById("wedit-content").value );
}
function wEditBox_showPreview() {
new mw.Api().get({
"action": "parse",
"title": mw.config.get("wgPageName"),
"text": document.getElementById('wedit-content').value,
"prop": "text|categories|templates|limitreporthtml",
"disableeditsection": 1,
"preview": 1,
"pst": 1,
"formatversion": "2",
}).then(function(ret) {
document.getElementById('wedit-previewContent').innerHTML = ret.parse.text["*"] + ret.parse.limitreporthtml["*"];
}, function(error, errorData){
mw.notify("Error occurred: " + JSON.stringify(errorData), {type: "error"})
})
}
function wEditBox_undo() {
if (wEditData.undoIndex > 0) {
var textarea = document.getElementById("wedit-content");
textarea.focus();
wEditData.lastUndoType = "";
wEditData.undoIndex -= 1;
textarea.value = wEditData.undo_hisory[wEditData.undoIndex];
textarea.selectionStart = wEditData.undo_hisory_cursor[wEditData.undoIndex];
textarea.selectionEnd = textarea.selectionStart;
document.getElementById("wedit-undo").disabled = !wEditData.undoIndex > 0
document.getElementById("wedit-redo").disabled = wEditData.undoIndex+1 >= wEditData.undo_hisory.length
}
}
function wEditBox_redo() {
if (wEditData.undoIndex+1 < wEditData.undo_hisory.length) {
var textarea = document.getElementById("wedit-content");
textarea.focus();
wEditData.lastUndoType = "";
wEditData.undoIndex += 1;
textarea.value = wEditData.undo_hisory[wEditData.undoIndex];
textarea.selectionStart = wEditData.undo_hisory_cursor[wEditData.undoIndex];
textarea.selectionEnd = textarea.selectionStart;
document.getElementById("wedit-undo").disabled = !wEditData.undoIndex > 0
document.getElementById("wedit-redo").disabled = wEditData.undoIndex+1 >= wEditData.undo_hisory.length
}
}
// Insert text to the textbox
function wEditBox_insertText(text){
var textarea = document.getElementById("wedit-content");
// Make sure to insert it at the cursor position
var newCursorPosition = textarea.selectionStart + text.length;
textarea.focus();
textarea.value = textarea.value.substring(0, textarea.selectionStart) + text + textarea.value.substring(textarea.selectionEnd, textarea.value.length);
// Set the cursor to be after the inserted text
textarea.selectionStart = newCursorPosition;
textarea.selectionEnd = newCursorPosition;
}
function wEditBox_summaryOnKeyPress(event){
// If player pressed the enter key in the summary box, post the edit.
if(event.key === "Enter") wEditBox_saveEdit();
}
function wEditBox_saveEdit() {
// Make sure the user can't spam the save button, which may cause unexpected behaviour.
document.getElementById("wedit-save-edit").disabled = true;
// Create this page
if (wEditData.is_new_page) {
new mw.Api().create(mw.config.get("wgPageName"), {
summary: document.getElementById('wedit-summary').value,
watchlist: document.getElementById("wedit-watch").checked ? "watch" : "unwatch"
}, document.getElementById('wedit-content').value
).then(function(){
// Page saved, open it
location.href = "https://" + mw.config.get("wgServerName") + "/wiki/" + mw.config.get("wgPageName");
}, function(e){
mw.notify("Cannot save page. Error: " + e);
});
// Editing the entire page
} else if (wEditData.edit_section === -1) {
new mw.Api().edit(mw.config.get("wgPageName"), function(revision) {
return {
text: document.getElementById('wedit-content').value,
summary: document.getElementById('wedit-summary').value,
minor: document.getElementById("wedit-minor").checked,
watchlist: document.getElementById("wedit-watch").checked ? "watch" : "unwatch"
}
}).then(function(){
// Page saved, open it
location.href = "https://" + mw.config.get("wgServerName") + "/wiki/" + mw.config.get("wgPageName");
}, function(e){
mw.notify("Cannot save page. Error: " + e);
});
// Editing a specific section
} else {
new mw.Api().edit(mw.config.get("wgPageName"), function(revision) {
return {
text: document.getElementById('wedit-content').value,
section: wEditData.edit_section,
summary: document.getElementById('wedit-summary').value,
minor: document.getElementById("wedit-minor").checked,
watchlist: document.getElementById("wedit-watch").checked ? "watch" : "unwatch"
}
}).then(function(){
// Page saved, open it
location.href = "https://" + mw.config.get("wgServerName") + "/wiki/" + mw.config.get("wgPageName");
}, function(e){
mw.notify("Cannot save page. Error: " + e);
});
}
}
// Saves the current text of the text editor as a new item in the undo history
function wEditBox_storeUndoableAction(){
if (wEditData.undoRedoCooldown) return; // This line is very important, do not remove, or it will result in empty undo history
// Get the textarea
var textarea = document.getElementById("wedit-content");
// Delete all undoable actions after this one, if the user has pressed redo
if (wEditData.undoIndex+1 < wEditData.undo_hisory.length) {
wEditData.undo_hisory.length = wEditData.undoIndex + 1;
wEditData.undo_hisory_cursor.length = wEditData.undoIndex + 1;
}
// Store the undo history data
wEditData.lastUndoType = "";
wEditData.undoIndex += 1;
wEditData.undo_hisory.push(textarea.value);
wEditData.undo_hisory_cursor.push(textarea.selectionStart);
document.getElementById("wedit-undo").disabled = !wEditData.undoIndex > 0
document.getElementById("wedit-redo").disabled = wEditData.undoIndex+1 >= wEditData.undo_hisory.length
}
function wEditBox_insertTemplateBrackets() {
wEditBox_insertText("{{}}");
// Set cursor to be in between the brackets
var textarea = document.getElementById("wedit-content");
textarea.selectionStart -= 2;
textarea.selectionEnd -= 2;
// Make this action undoble
wEditBox_storeUndoableAction();
}
function wEditBox_insertWikiLink() {
wEditBox_insertText("[[]]");
// Set cursor to be in between the brackets
var textarea = document.getElementById("wedit-content");
textarea.selectionStart -= 2;
textarea.selectionEnd -= 2;
// Make this action undoble
wEditBox_storeUndoableAction();
}
function replaceAll(text, replace, to_text){
return text.split(replace).join(to_text)
}