Editing.js – MediaWiki
Jump to navigation
Jump to search
Lou Montana (talk | contribs) (Add Ctrl+B / Ctrl+I shortcuts) |
Lou Montana (talk | contribs) m (Fix?) |
||
Line 384: | Line 384: | ||
allowTabs(); | allowTabs(); | ||
mw.loader.using( 'user.options' ).then( function () { | |||
if ( mw.user.options.get( 'usebetatoolbar' ) == 1 ) { | |||
$.when( | |||
mw.loader.using( 'ext.wikiEditor' ), $.ready | |||
).then( allowCtrlBI ); | |||
} | |||
} | |||
); | |||
darkModePreview(); | darkModePreview(); | ||
allowLineMoveAndDuplication(); | allowLineMoveAndDuplication(); | ||
}()); // END WRAPPER | }()); // END WRAPPER |
Revision as of 11:34, 18 September 2024
/*****************************************************************************************
* JavaScript here will be loaded by MediaWiki:Common.js when "editing mode" is detected.
*
*****************************************************************************************/
(function() { // BEGIN WRAPPER
/*****************************************************************************************
* Variables required by all functions below
*/
var editingTextbox = document.getElementById("wpTextbox1");
/*****************************************************************************************
* Add checkbox toggle of allowance to use TAB key in editing textarea to insert TAB chars
* Maintainer: [[User:Fred Gandt]]
*/
function allowTabs() {
var ecb = document.getElementsByClassName("editCheckboxes")[0],
cb = document.createElement("input"),
cb_lbl = document.createElement("label"),
tabsAllowed = function(evt) {
if (evt.keyCode == 9) {
evt.preventDefault();
var ss = editingTextbox.selectionStart;
editingTextbox.value = editingTextbox.value.substr(0, ss) + String.fromCharCode(evt.keyCode) + editingTextbox.value.substr(editingTextbox.selectionEnd);
editingTextbox.setSelectionRange(ss + 1, ss + 1);
}
}
initTabsAllowed = function() {
editingTextbox.addEventListener("keydown", tabsAllowed, false);
editingTextbox.form.action += "&allowTabs";
};
cb.setAttribute("id", "allowTabs");
cb.setAttribute("type", "checkbox");
cb.setAttribute("style", "margin-left: 3em");
cb_lbl.setAttribute("for", "allowTabs");
cb_lbl.setAttribute("title", "Allows insertion of Tab characters when and where the Tab key is pressed");
cb_lbl.innerHTML = " Allow tabulations usage";
cb.addEventListener("change", function() {
if (this.checked) {
initTabsAllowed();
} else {
editingTextbox.removeEventListener("keydown", tabsAllowed, false);
editingTextbox.form.action = editingTextbox.form.action.replace("&allowTabs", "");
}
}, false);
if (~window.location.search.indexOf("&allowTabs")) {
cb.checked = true;
initTabsAllowed();
}
ecb.appendChild(cb);
ecb.appendChild(cb_lbl);
}
/*****************************************************************************************
* Prevents page body scrolling when scrolling of the editing textarea reaches the top or bottom.
* Maintainer: [[User:Fred Gandt]]
*/
function holdStill() {
editingTextbox.addEventListener("mousewheel", function(evt) {
evt.preventDefault();
editingTextbox.scrollTop -= evt.wheelDelta / 3;
}, false);
}
/*****************************************************************************************
* Add a checkbox to preview darkmode (?useskin=darkvector)
* Maintainer: [[User:Lou Montana]]
*/
function darkModePreview() {
var ecb = document.getElementsByClassName("editCheckboxes")[0],
cb = document.createElement("input"),
label = document.createElement("label"),
actionDarkAdd = "&useskin=darkvector";
actionLightAdd = "&useskin=vector";
cb.setAttribute("id", "previewDarkMode");
cb.setAttribute("type", "checkbox");
cb.setAttribute("style", "margin-left: 3em");
label.setAttribute("for", "previewDarkMode");
label.setAttribute("title", "Preview Dark Mode render (next preview)");
label.innerHTML = " Preview Dark Mode";
cb.addEventListener("change", function() {
if (this.checked) {
editingTextbox.form.action = editingTextbox.form.action.replace(actionLightAdd, "")
editingTextbox.form.action += actionDarkAdd;
} else {
editingTextbox.form.action = editingTextbox.form.action.replace(actionDarkAdd, "");
editingTextbox.form.action += actionLightAdd;
}
}, false);
cb.checked = document.getElementsByTagName("body")[0].classList.contains("skin-darkvector");
let event = new Event("change");
cb.dispatchEvent(event);
ecb.appendChild(cb);
ecb.appendChild(label);
}
/*****************************************************************************************
* Allow Ctrl+B / Ctrl+I to trigger B/I source edit mode button
* Maintainer: [[User:Lou Montana]]
*/
function allowCtrlBI() {
let boldButton;
let boldElements = document.getElementsByClassName('oo-ui-iconElement-icon oo-ui-icon-bold');
if (boldElements.length > 0)
boldButton = boldElements[0].parentNode;
let italicButton;
let italicElements = document.getElementsByClassName('oo-ui-iconElement-icon oo-ui-icon-italic');
if (italicElements.length > 0)
italicButton = italicElements[0].parentNode;
if (!boldButton && !italicButton)
{
alert('no bold nor italic found');
return;
}
document.getElementById('wpTextbox1').addEventListener('keydown', (ev) => {
let textAreaElement = document.getElementById('wpTextbox1');
if (!textAreaElement)
return;
if (ev.altKey || !ev.ctrlKey || ev.shiftKey)
return;
if (ev.key == 'b')
{
if (!boldButton)
return false;
// boldButton.dispatchEvent(new Event('click', { bubbles: true, defaultPrevented: true }));
// boldButton.dispatchEvent(new CustomEvent('click'));
ev.preventDefault();
boldButton.click();
return true;
}
if (ev.key == 'i')
{
if (!italicButton)
return false;
ev.preventDefault();
italicButton.click();
return true;
}
});
}
if ( [ 'edit', 'submit' ].indexOf( mw.config.get( 'wgAction' ) ) !== -1 ) {
mw.loader.using( 'user.options' ).then( function () {
if ( mw.user.options.get( 'usebetatoolbar' ) == 1 ) {
$.when(
mw.loader.using( 'ext.wikiEditor' ), $.ready
).then( addCtrlBI );
}
} );
}
/*****************************************************************************************
* Allow moving source code textarea's selected line(s) with Alt+Up / Alt+Down
* Allow duplicating source code textarea's selected line(s) with Alt+Shift+Up / Alt+Shift+Down
* Allow duplicating code textarea's current line/selection with Ctrl+D
* Maintainer: [[User:Lou Montana]]
*/
function allowLineMoveAndDuplication() {
editingTextbox.addEventListener('keydown', (ev) => {
// duplicate line below
if (ev.ctrlKey && !ev.altKey && !ev.shiftKey && (ev.key == 'd' || ev.key == 'D')) // Ctrl+D
{
duplicateSelection(editingTextbox);
ev.preventDefault();
return;
}
if (ev.key != 'ArrowUp' && ev.key != 'ArrowDown')
return;
let up = ev.key == 'ArrowUp';
// move line(s) up/down
if (!ev.ctrlKey && ev.altKey && !ev.shiftKey) // Alt up/down
{
moveLines(editingTextbox, up);
return;
}
// duplicate line(s) up/down
if (!ev.ctrlKey && ev.altKey && ev.shiftKey) // Alt+Shift+Up/Down
{
duplicateLines(editingTextbox, up);
return;
}
});
}
/**
*
* @param {HTMLTextAreaElement} editingTextbox
* @param {bool} moveUp
*/
function moveLines(editingTextbox, moveUp) {
let lines = editingTextbox.value.split('\n');
let linesCount = lines.length;
if (linesCount < 1)
return;
let [firstHighlightedLine, lastHighlightedLine] = getHighlightedLines(lines, editingTextbox.selectionStart, editingTextbox.selectionEnd);
if ((moveUp && firstHighlightedLine == 0) || (!moveUp && lastHighlightedLine == linesCount - 1))
return;
let selectionStart = editingTextbox.selectionStart;
let selectionEnd = editingTextbox.selectionEnd;
if (moveUp)
{
let movedLine = lines[firstHighlightedLine - 1];
lines.splice(firstHighlightedLine - 1, 1);
lines.splice(lastHighlightedLine, 0, movedLine);
selectionStart -= movedLine.length + 1;
selectionEnd -= movedLine.length + 1;
}
else
{
let movedLine = lines[lastHighlightedLine + 1];
lines.splice(lastHighlightedLine + 1, 1);
lines.splice(firstHighlightedLine, 0, movedLine);
selectionStart += movedLine.length + 1;
selectionEnd += movedLine.length + 1;
}
setTextAreaValue(editingTextbox, lines, selectionStart, selectionEnd);
}
/**
* triggered by Ctrl+D
* @param {HTMLTextAreaElement} editingTextbox
*/
function duplicateSelection(editingTextbox) {
let originalValue = editingTextbox.value;
// no selection; duplicate current line below
if (editingTextbox.selectionStart == editingTextbox.selectionEnd)
{
let lines = originalValue.split('\n');
let [firstHighlightedLine] = getHighlightedLines(lines, editingTextbox.selectionStart, editingTextbox.selectionEnd);
lines.splice(firstHighlightedLine, 0, lines[firstHighlightedLine]);
setTextAreaValue(editingTextbox, lines);
return;
}
// selection that should simply be inserted after the selection
let selection = originalValue.substring(editingTextbox.selectionStart, editingTextbox.selectionEnd);
originalValue = originalValue.slice(0, editingTextbox.selectionEnd) + selection + originalValue.slice(editingTextbox.selectionEnd);
let lines = originalValue.split('\n');
setTextAreaValue(editingTextbox, lines);
}
/**
* @param {HTMLTextAreaElement} editingTextbox
* @param {bool} dupeUp
*/
function duplicateLines(editingTextbox, dupeUp) {
let lines = editingTextbox.value.split('\n');
let linesCount = lines.length;
let [firstHighlightedLine, lastHighlightedLine] = getHighlightedLines(lines, editingTextbox.selectionStart, editingTextbox.selectionEnd);
if ((dupeUp && firstHighlightedLine == 0) || (!dupeUp && lastHighlightedLine == linesCount - 1))
return;
let selectionStart = editingTextbox.selectionStart;
let selectionEnd = editingTextbox.selectionEnd;
if (dupeUp)
{
let selectionOffset = 0;
for (let i = firstHighlightedLine; i < lastHighlightedLine + 1; ++i)
{
selectionOffset += lines[i].length + 1;
lines.splice(firstHighlightedLine, 0, lines[i]);
}
selectionStart += selectionOffset;
selectionEnd += selectionOffset;
}
else
{
for (let i = lastHighlightedLine; i >= firstHighlightedLine; --i)
{
lines.splice(lastHighlightedLine + 1, 0, lines[i]);
}
}
setTextAreaValue(editingTextbox, lines, selectionStart, selectionEnd);
}
/**
*
* @param {HTMLTextAreaElement} editingTextbox
* @param {array} lines
* @returns {array} [firstHighlightedLine, lastHighlightedLine, selectionStartColumn, selectionEndColumn]
*/
function getHighlightedLines(lines, selectionStart, selectionEnd) {
let linesCount = lines.length;
let firstHighlightedLine = -1;
let lastHighlightedLine = -1;
let selectionStartColumn = -1;
let selectionEndColumn = -1;
let calcLength = 0;
let lineLength;
for (let i = 0; i < linesCount; ++i) {
lineLength = lines[i].length;
if (selectionStartColumn == -1 && selectionStart <= calcLength + lineLength) {
firstHighlightedLine = i;
selectionStartColumn = selectionStart - calcLength;
}
if (selectionEndColumn == -1 && selectionEnd <= calcLength + lineLength) {
lastHighlightedLine = i;
selectionEndColumn = selectionStart - calcLength;
}
if (selectionEndColumn != -1 && selectionEndColumn != -1)
break;
calcLength += lineLength + 1; // "\n"
}
if (selectionStartColumn == -1 || selectionEndColumn == -1)
return;
if (firstHighlightedLine < lastHighlightedLine)
return [firstHighlightedLine, lastHighlightedLine, selectionStartColumn, selectionEndColumn];
else
return [lastHighlightedLine, firstHighlightedLine, selectionStartColumn, selectionEndColumn];
}
/**
*
* @param {HTMLTextAreaElement} editingTextbox
* @param {Array} lines
* @param {number} selectionStart
* @param {number} selectionEnd
*/
function setTextAreaValue(editingTextbox, lines, selectionStart, selectionEnd) {
if (!selectionStart && selectionStart !== 0)
selectionStart = editingTextbox.selectionStart;
if (!selectionEnd && selectionEnd !== 0)
selectionEnd = editingTextbox.selectionEnd;
// editingTextbox.value = lines.join('\n');
editingTextbox.select();
document.execCommand('insertText', false, lines.join('\n'));
editingTextbox.selectionStart = selectionStart;
editingTextbox.selectionEnd = selectionEnd;
}
/*****************************************************************************************
* Call the required functions from those above
*/
allowTabs();
mw.loader.using( 'user.options' ).then( function () {
if ( mw.user.options.get( 'usebetatoolbar' ) == 1 ) {
$.when(
mw.loader.using( 'ext.wikiEditor' ), $.ready
).then( allowCtrlBI );
}
}
);
darkModePreview();
allowLineMoveAndDuplication();
}()); // END WRAPPER