CURRENT MISSION: Conclude the 2026 soyjak.party hack page, aswell as any pages relating to it, such as the Summer 2026 Crisis page.
Update Quotecord with any relevant info. See the blackboard for more info.
User:Tar/common.js
From Soyjak Wiki, the free ensoyclopedia
< User:Tar
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.
(function () {
'use strict';
if (!['edit', 'submit'].includes(mw.config.get('wgAction'))) {
return;
}
const config = {
minimumCharacters: 2,
maximumResults: 5,
searchDelay: 200,
usernameInsertFormat: '@[[User:$1]] ',
emojiInsertFormat: '{{e|$1}} '
};
const emojis = [
'abdul', 'ack', 'alien', 'angel', 'brainlet', 'caca', 'calm',
'cat', 'chang', 'cheeky', 'cheers', 'clittycel', 'clown',
'coal', 'cold', 'concerned', 'cool', 'coomer', 'coping',
'disgusted', 'diva', 'dog', 'dreamy', 'esl', 'euro', 'fact',
'false', 'feelsgoodman', 'flushed', 'fruity', 'fuming', 'gem',
'giga', 'glowie', 'heartbroken', 'hearts', 'holdit', 'horny',
'hot', 'hunk', 'imp', 'informative', 'irritated', 'itsover',
'jamming', 'jarty', 'jsid', 'kaching', 'kek', 'keyed', 'kumar',
'locked', 'looking', 'marge', 'meds', 'mexi', 'mutt',
'nailbiter', 'neutral', 'nophono', 'omgsisa', 'pleading',
'poon', 'projecting', 'rage', 'reddit', 'robot', 'sad',
'schizo', 'serious', 'shush', 'dough', 'sick', 'skull',
'sleeping', 'slf', 'smart', 'smoking', 'smug', 'smugjak',
'snca', 'sob', 'soyboy', 'soytan', 'spade', 'steiner',
'surprised', 'suspicious', 'tendie', 'thinking', 'though',
'thumbsdown', 'thumbsup', 'tired', 'tism', 'true', 'tsmt',
'turk', 'tyrone', 'unc', 'uncomfortable', 'wholesome',
'xitter', 'yum', 'zany', 'dodis', 'arrow', 'ijgs', 'genius'
];
let codeMirror;
let activeCompletion;
let results = [];
let selectedIndex = 0;
let debounceTimer;
let apiPromise = null;
const menu = document.createElement('div');
menu.className = 'username-autocomplete';
menu.hidden = true;
document.body.appendChild(menu);
function getApi() {
if (!apiPromise) {
apiPromise = mw.loader
.using('mediawiki.api')
.then(function () {
return new mw.Api();
});
}
return apiPromise;
}
function getCodeMirrorFromEvent(event) {
const wrapper = event.target instanceof Element && event.target.closest('.CodeMirror');
return wrapper ? wrapper.CodeMirror : null;
}
function getCompletion(cm) {
const cursor = cm.getCursor();
const before = cm.getLine(cursor.line).slice(0, cursor.ch);
let match = before.match(
/(?:^|[\s([{"'])@([^@\n\r\t<>{}\[\]|#/:;,!?]*)$/
);
let type = 'username';
if (!match) {
match = before.match(
/(?:^|[\s([{"']):([a-zA-Z0-9_-]*)$/
);
type = 'emoji';
}
if (!match) {
return null;
}
const query = match[1];
return {
type,
query,
start: {
line: cursor.line,
ch: cursor.ch - query.length - 1
},
end: cursor
};
}
function completionsMatch(a, b) {
return (
a &&
b &&
a.type === b.type &&
a.query === b.query &&
a.start.line === b.start.line &&
a.start.ch === b.start.ch &&
a.end.line === b.end.line &&
a.end.ch === b.end.ch
);
}
function hideMenu() {
menu.hidden = true;
menu.replaceChildren();
activeCompletion = null;
results = [];
selectedIndex = 0;
}
function positionMenu() {
if (!codeMirror) {
return;
}
const pos = codeMirror.cursorCoords(null, 'page');
menu.style.left = pos.left + 'px';
menu.style.top = pos.bottom + 'px';
}
function setSelectedIndex(index) {
const items = menu.querySelectorAll(
'.username-autocomplete-result'
);
if (!items.length) {
return;
}
selectedIndex = (index + items.length) % items.length;
items.forEach((item, i) => {
item.classList.toggle(
'selected',
i === selectedIndex
);
});
}
function insertResult(value) {
if (!codeMirror || !activeCompletion) {
return;
}
const format =
activeCompletion.type === 'emoji'
? config.emojiInsertFormat
: config.usernameInsertFormat;
const insertion = format.replaceAll('$1', value);
codeMirror.replaceRange(
insertion,
activeCompletion.start,
activeCompletion.end,
'+autocomplete'
);
codeMirror.setCursor({
line: activeCompletion.start.line,
ch: activeCompletion.start.ch + insertion.length
});
codeMirror.focus();
hideMenu();
}
function renderResults(values) {
menu.replaceChildren();
results = values;
selectedIndex = 0;
if (!values.length) {
const empty = document.createElement('div');
empty.className = 'username-autocomplete-empty';
empty.textContent =
activeCompletion.type === 'emoji'
? 'No matching emojis'
: 'No matching users';
menu.appendChild(empty);
} else {
values.forEach((value, index) => {
const item = document.createElement('div');
item.className = 'username-autocomplete-result';
if (index === 0) {
item.classList.add('selected');
}
if (activeCompletion.type === 'emoji') {
const img = document.createElement('img');
img.src =
mw.config.get('wgScriptPath') +
'/index.php?title=Special:Redirect/file/' +
encodeURIComponent( 'Nuuru ' + value.toLowerCase() + '.png')
img.alt = value;
item.append(img, document.createTextNode(' ' + value));
} else {
item.textContent = value;
}
item.addEventListener(
'mouseenter',
() => setSelectedIndex(index)
);
item.addEventListener(
'mousedown',
event => {
event.preventDefault();
insertResult(value);
}
);
menu.appendChild(item);
});
}
menu.hidden = false;
positionMenu();
}
function searchUsers(cm, completion) {
getApi()
.then(function (api) {
return api.get({
action: 'query',
list: 'allusers',
auprefix: completion.query,
aulimit: config.maximumResults,
formatversion: 2
});
})
.then(function (data) {
const current = getCompletion(cm);
if (!completionsMatch(current, completion)) {
return;
}
codeMirror = cm;
activeCompletion = current;
renderResults(
(data.query.allusers || []).map(
user => user.name
)
);
})
.catch(function (error) {
console.error(
'Username autocomplete API error:',
error
);
hideMenu();
});
}
function searchEmojis(cm, completion) {
const current = getCompletion(cm);
if (!completionsMatch(current, completion)) {
return;
}
codeMirror = cm;
activeCompletion = current;
const query = completion.query.toLowerCase();
renderResults(
emojis
.filter(emoji =>
emoji.startsWith(query)
)
.slice(0, config.maximumResults)
);
}
function processEditor(cm) {
const completion = getCompletion(cm);
if (
!completion ||
completion.query.length <
config.minimumCharacters
) {
clearTimeout(debounceTimer);
hideMenu();
return;
}
codeMirror = cm;
activeCompletion = completion;
clearTimeout(debounceTimer);
if (completion.type === 'emoji') {
searchEmojis(cm, completion);
return;
}
debounceTimer = setTimeout(
() => searchUsers(cm, completion),
config.searchDelay
);
}
document.addEventListener(
'keyup',
event => {
const cm = getCodeMirrorFromEvent(event);
if (
!cm ||
[
'ArrowUp',
'ArrowDown',
'Enter',
'Tab',
'Escape'
].includes(event.key)
) {
return;
}
processEditor(cm);
},
true
);
document.addEventListener(
'keydown',
event => {
if (
menu.hidden ||
getCodeMirrorFromEvent(event) !== codeMirror
) {
return;
}
switch (event.key) {
case 'ArrowDown':
event.preventDefault();
event.stopPropagation();
setSelectedIndex(selectedIndex + 1);
break;
case 'ArrowUp':
event.preventDefault();
event.stopPropagation();
setSelectedIndex(selectedIndex - 1);
break;
case 'Enter':
case 'Tab':
if (results.length) {
event.preventDefault();
event.stopPropagation();
insertResult(
results[selectedIndex]
);
}
break;
case 'Escape':
event.preventDefault();
event.stopPropagation();
hideMenu();
break;
}
},
true
);
document.addEventListener('mousedown', event => {
if (
!menu.contains(event.target) &&
!(
event.target instanceof Element &&
event.target.closest('.CodeMirror')
)
) {
hideMenu();
}
});
window.addEventListener('resize', () => {
if (!menu.hidden) {
positionMenu();
}
});
}());