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.
/**
* Adds numbers to each line of code in a codeblock.
* // current update is for mw version `1.39.3`
* @name CodeblockLineNumbers
* @author Arashiryuu0
* @version 1.2.4
* Last modified: 1682579289295
*/
/*
jshint
undef: true,
noarg: true,
devel: true,
jquery: true,
strict: true,
eqeqeq: true,
freeze: true,
newcap: true,
esnext: true,
browser: true,
latedef: true,
shadow: outer,
varstmt: false,
laxbreak: true,
quotmark: single,
singleGroups: true,
futurehostile: true
*/
/*
globals
Symbol
*/
;(function (mw) {
'use strict';
if (window.dev && window.dev.CodeblockLineNumbers) return;
var classes = [
'lineNumbers',
parseInt(mw.config.get('wgVersion').split('.')[1]) < 37
? null
: 'obs'
].filter(Boolean);
var codeblocks = [
['de1', 'hljs'],
['theme-solarized-light', 'theme-solarized-dark'],
['.mw-highlight pre', 'code pre', '.pi-data-value pre']
],
slice = Array.prototype.slice,
ourblocks = slice.call(document.querySelectorAll('pre'));
if (!ourblocks.length) return;
window.importArticles({
type: 'style',
articles: ['u:dev:MediaWiki:CodeblockLineNumbers.css']
});
function noOl (codeblock) {
return !codeblock.querySelector('ol');
}
function mapLine (line) {
if (!!line) return '<li>' + line + '</li>';
}
function addLines (codeblock) {
codeblock.innerHTML = codeblock.innerHTML
.split('\n')
.map(mapLine)
.join('');
return codeblock;
}
function ourFilter (codeblock) {
var hasId = function () {
return codeblocks[1].includes(codeblock.getAttribute('id'));
};
var hasClass = function () {
return codeblocks[0].some(function (name) {
return codeblock.classList && codeblock.classList.contains(name);
});
};
var ucpBlock = function () {
return codeblocks[2].some(function (selector) {
return codeblock.matches(selector);
});
};
if (codeblock.tagName === 'PRE' && codeblock.parentElement.tagName !== 'PRE') {
return hasId() || hasClass() || ucpBlock();
}
return false;
}
function combineFilters () {
var filters = slice.call(arguments);
return function (codeblock) {
var callback = function (filter) {
return filter(codeblock);
};
return filters.every(callback);
};
}
function wrapInner (parent, wrapper) {
if (typeof wrapper === 'string') wrapper = document.createElement(wrapper);
parent.appendChild(wrapper);
while (parent.firstChild !== wrapper) wrapper.appendChild(parent.firstChild);
}
function isCommentStart (child) {
return child.textContent.trim().startsWith('/*');
}
function isInlineComment (child) {
var blockClasses = ['coMULTI', 'hljs-comment'],
hasClass = function () {
var a = Boolean(child.className) && blockClasses.includes(child.className),
b = Boolean(child.firstElementChild)
&& blockClasses.includes(child.firstElementChild.className);
return a || b;
},
starts = child.textContent.trim().startsWith('/*'),
ends = child.textContent.trim().endsWith('*/');
return (hasClass() && starts && ends) || starts && ends; // jshint ignore: line
}
function getEndIndex (i) {
return function (child, ind) {
var greater = ind > i,
trimmed = child.textContent.trim(),
ends = trimmed[0] === '*' && trimmed.endsWith('*/');
return Boolean(greater && ends);
};
}
function mapSlicedChildren (child) {
return child.cloneNode(true);
}
function createUL () {
var ul = document.createElement('ul');
ul.classList.add('no-list');
return ul;
}
function remove (t) {
t.parentElement.removeChild(t);
}
function filterSliced (group) {
return function (children, index) {
var a = index >= group.start || index <= group.end,
b = children.tagName !== 'UL';
return a && b;
};
}
function addCommentGroup (codeblock, group) {
var children, filtered, fn, end, pe, cn;
pe = codeblock.parentElement;
cn = pe.className === 'de1' || pe.getAttribute('id');
group.parent.classList.add(cn ? 'coMULTI' : 'hljs-comment');
for (var i = 0, len = group.children.length; i < len; i++) {
group.parent.appendChild(group.children[i]);
}
end = codeblock.children[group.end];
if (codeblock.children.length - 1 === group.end) {
codeblock.appendChild(group.parent);
} else if (end) {
end.insertAdjacentElement('afterend', group.parent);
}
fn = filterSliced(group);
children = slice.call(codeblock.children);
filtered = children.slice(group.start, group.end + 1).filter(fn);
for (i = 0, len = filtered.length; i < len; i++) {
remove(filtered[i]);
}
}
function parseComments (codeblock) {
var groups = [],
children = slice.call(codeblock.children),
sliced;
for (var i = 0, len = children.length; i < len; i++) {
var start = 0, end = 0, child = children[i];
if (!isCommentStart(child) || isInlineComment(child)) continue;
start = i;
end = children.findIndex(getEndIndex(start));
sliced = children.slice(start, end + 1).map(mapSlicedChildren);
groups.push({
start: start,
end: end,
parent: createUL(),
children: sliced
});
}
if (!groups.length) return;
for (i = groups.length - 1, len = 0; i >= len; i--) {
addCommentGroup(codeblock, groups[i]);
}
}
function match (block, selector) {
return block.matches(selector);
}
function processCodeblock (block) {
if (block.querySelector('ol.lineNumbers')) return;
var ol = document.createElement('ol'),
matched = match(block, codeblocks[2][1]),
ignore = match(block, codeblocks[2][2]);
if (ignore) return;
ol.classList.add.apply(ol.classList, classes);
if (!block.parentElement.classList.contains('mw-highlight-lines')) ol.classList.remove('obs');
/**
* weird edge-case, <syntaxhighlight line> element but doesn't render any linenos?
* see Luxon for reference {@link https://sky-children-of-the-light.fandom.com/wiki/MediaWiki:Luxon.js}
*/
if (block.matches('.mw-highlight-lines pre') && !block.querySelector('.linenos')) ol.classList.remove('obs');
wrapInner(addLines(block), ol);
/** remove empty trailing <li>s */
if (!ol.lastElementChild.childNodes.length) ol.removeChild(ol.lastElementChild);
if (matched || !mw.user.getRights) parseComments(ol);
}
function processCodeblocks () {
var filtered = ourblocks.filter(combineFilters(noOl, ourFilter)),
len = filtered.length;
if (!len) return;
for (var i = 0; i < len; i++) processCodeblock(filtered[i]);
}
var defaults = {
ready: true
};
var obj = {
processBlock: processCodeblock,
process: processCodeblocks,
settings: Object.assign({}, defaults, window.CodeblockLinesConfig)
};
Object.defineProperty(obj, Symbol.toStringTag, {
configurable: false,
writable: false,
value: 'CodeblockLineNumbers'
});
Object.freeze(obj);
window.dev = window.dev || {};
window.dev.CodeblockLineNumbers = obj;
function fire () {
var lines = window.dev.CodeblockLineNumbers;
var settings = lines.settings;
if (typeof settings.delay === 'number' && !Number.isNaN(settings.delay) && settings.delay >= 0) {
setTimeout(lines.process, settings.delay);
} else if (typeof settings.loadAction === 'function') {
settings.loadAction(lines);
} else if (settings.ready) {
lines.process();
}
mw.hook('dev.CodeblockLineNumbers').fire(lines);
}
function ready () {
if (document.readyState !== 'complete') return setTimeout(ready, 1000);
setTimeout(fire, 1);
}
ready();
})(window.mediaWiki);
/*@end@*/