User:Nardog/AutoSectionLink.js

['edit', 'submit'].includes(mw.config.get('wgAction')) &&

mw.config.get('wgArticleId') &&

mw.config.get('wgPageContentModel') === 'wikitext' &&

$(function autoSectionLink() {

let form = document.getElementById('editform');

if (!form) return;

let formData = new FormData(form);

let section = formData.get('wpSection');

if (section === 'new') return;

let widget = document.getElementById('wpSummaryWidget');

if (!widget) return;

let isOld = formData.get('altBaseRevId') > 0 ||

(formData.get('baseRevId') || formData.get('parentRevId')) !== formData.get('editRevId');

mw.loader.using([

'jquery.textSelection', 'mediawiki.util', 'oojs-ui-core',

'oojs-ui.styles.icons-editing-core'

], () => {

let $textarea = $('#wpTextbox1');

let input = OO.ui.infuse(widget);

let button = new OO.ui.ButtonWidget({

framed: false,

icon: 'undo',

classes: ['autosectionlink-button'],

invisibleLabel: true,

label: 'Restore previous section link'

}).toggle().on('click', () => {

let cache = button.getData();

input.setValue(input.getValue().replace(

/^(\/\*.*?\*\/)?\s*/,

cache[0] ? '/* ' + cache[0] + ' */ ' : ''

));

updatePreview(cache[0]);

cache.reverse();

}).on('toggle', () => {

input.$input.css('width', `calc(100% - ${button.$element.width()}px)`);

});

input.$input.after(button.$element);

let update = mw.util.debounce($diff => {

let lines = $textarea.textSelection('getContents').replace(/\s+$/, '').split('\n');

let firstLineNum;

if (isOld) {

let i, lastLineNum;

$diff.find('td:last-child').each(function () {

if (this.classList.contains('diff-lineno')) {

i = this.textContent.replace(/\D+/g, '') - 1;

} else if (this.classList.contains('diff-context')) {

i++;

} else if (this.classList.contains('diff-addedline')) {

i++;

if (!firstLineNum) {

firstLineNum = i;

}

lastLineNum = i;

} else if (this.classList.contains('diff-empty')) {

if (!firstLineNum) {

firstLineNum = i === 0 ? 1 : i;

}

lastLineNum = i;

}

});

lines.length = lastLineNum || 0;

} else {

let origLines = $textarea.prop('defaultValue').replace(/\s+$/, '').split('\n');

firstLineNum = lines.findIndex((line, i) => line !== origLines[i]) + 1;

if (!firstLineNum) {

firstLineNum = lines.length < origLines.length

? lines.length

: 1;

}

for (let i = 1, x = lines.length, y = origLines.length;

(section ? i < x : i <= x) && lines[x - i] === origLines[y - i];

i++

) {

lines.pop();

}

}

let re = /^(={1,6})\s*(.+?)\s*\1\s*(?:\s*)?$/, lowest = 7;

lines.slice(firstLineNum).forEach(line => {

let match = line.match(re);

if (match && match[1].length < lowest) {

lowest = match[1].length;

}

});

let head;

lines.slice(0, firstLineNum).reverse().some(line => {

let match = line.match(re);

if (match && match[1].length < lowest) {

head = match[2];

return true;

}

});

head = head ? head

.replace(/(.+?)|\[\[:?(?:[^|\]]+\|)?([^\]]+)\]\]|<\/?(?:abbr|b|bdi|bdo|big|cite|code|data|del|dfn|em|font|i|ins|kbd|mark|nowiki|q|rb|ref|rp|rt|rtc|ruby|s|samp|small|span|strike|strong|sub|sup|templatestyles|time|translate|tt|u|var)(?:\s[^>]*)?>||\[(?:https?:)?\/\/[^\s\[\]]+\s([^\]]+)\]/gi, '$1$2$3')

.replace(/(.+?)/g, '$1')

.trim() : '';

let match = input.getValue().match(/^(?:\/\*\s*(.*?)\s*\*\/)?\s*(.*?)$/);

let prev = match[1] || '';

if (prev === head) return;

if (section < 1 && lowest === 7 && !head && prev === 'top') return;

input.setValue((head ? '/* ' + head + ' */ ' : '') + match[2]);

button.setData([prev, head]).toggle(true);

updatePreview(head);

}, 500);

let updatePreview = head => {

let $preview = $('.mw-summary-preview > .comment > span[dir="auto"]');

if (!$preview.length) return;

let url = head && mw.util.getUrl() + '#' + head.replace(/ /g, '_');

let text = head && (document.dir === 'rtl' ? '←\u200F' : '→\u200E') + head;

let $ac = $preview.children('.autocomment:first-child');

if ($ac.length && !$ac[0].previousSibling) {

if (head) {

$ac.children('a').attr('href', url).text(text);

} else {

let node = $ac[0].nextSibling;

if (node && node.nodeType === 3) {

node.textContent = node.textContent.replace(/^\s+/, '');

}

$ac.remove();

}

} else if (head) {

$('').addClass('autocomment').append(

$('').attr({

href: url,

title: mw.config.get('wgPageName').replace(/_/g, ' ')

}).text(text),

mw.messages.get('colon-separator', ': ')

).prependTo($preview);

}

};

if (isOld) {

mw.hook('wikipage.diff').add(update);

} else {

$textarea.on('input', update);

mw.hook('ext.CodeMirror.switch').add((on, $codeMirror) => {

if (on && $codeMirror[0].CodeMirror) {

$codeMirror[0].CodeMirror.on('change', update);

}

});

mw.hook('ext.CodeMirror.input').add(update);

update();

}

});

mw.loader.addStyleTag('.autosectionlink-button{position:absolute;top:0;right:0;margin:0}');

});