riot-katex/riot-katex.js

120 lines
3.9 KiB
JavaScript
Raw Permalink Normal View History

2020-04-09 14:31:27 +02:00
(function() {
/**
* Check and set a global guard variable.
* If this content script is injected into the same page again,
* it will do nothing next time.
*/
if (window.hasRun) {
return;
}
2020-04-09 18:25:05 +02:00
window.hasRun = true;
2020-04-09 14:31:27 +02:00
2020-04-10 10:16:38 +02:00
const chat_class = '.mx_RoomView_MessageList';
const chat_item_class = '.mx_MTextBody';
2020-04-09 16:46:59 +02:00
/**
* Set up math delimiters.
*/
2020-04-27 13:09:08 +02:00
const math_config = {
delimiters :[
{left: "$$$", right: "$$$", display: true},
2020-04-27 18:24:36 +02:00
{left: "$$", right: "$$", display: false},
{left: "\\(", right: "\\)", display: false},
2020-04-27 13:09:08 +02:00
],
}
2020-04-09 14:31:27 +02:00
2020-04-09 18:25:05 +02:00
/**
* Render math in a node if it hasn't already be done
* and register an event on the edit button.
*/
2020-04-09 18:16:14 +02:00
function renderMath(node) {
2020-04-10 10:16:38 +02:00
if (!node)
return;
2020-04-09 18:16:14 +02:00
let li = node.closest('li');
2020-04-09 18:22:36 +02:00
2020-04-27 12:57:13 +02:00
let contentNodes = li.querySelectorAll('.mx_EventTile_body');
if (!content) {
2020-04-09 18:22:36 +02:00
return;
}
2020-04-27 12:57:13 +02:00
for (let content of contentNodes) {
if(content.getAttribute('originalContent') || content.getAttribute('editing')) // already rendered
continue;
2020-04-09 20:37:57 +02:00
2020-04-27 12:57:13 +02:00
let og_content = (' ' + content.textContent).slice(1);
2020-04-27 13:09:08 +02:00
//content.setAttribute('originalContent', og_content);
renderMathInElement(content, math_config);
2020-04-09 20:37:57 +02:00
}
2020-04-09 18:16:14 +02:00
}
2020-04-09 16:46:59 +02:00
/**
* Initialize Extension as soon as matrix has been loaded.
*/
2020-04-09 14:31:27 +02:00
function init() {
2020-04-09 16:46:59 +02:00
// render with KaTeX as soon as the message appears
2020-04-09 14:31:27 +02:00
function listen_on_chat_element() {
2020-04-10 10:16:38 +02:00
let chat_elem = document.querySelector(chat_class);
let chat_items = chat_elem.querySelectorAll(chat_item_class);
2020-04-09 20:37:57 +02:00
for(let node of chat_items) {
2020-04-09 18:16:14 +02:00
renderMath(node);
}
2020-04-09 14:31:27 +02:00
const callback = function(mutationsList, observer) {
for(let mutation of mutationsList) {
2020-04-09 18:16:14 +02:00
if(mutation.type === 'attributes' && mutation.attributeName === 'class') {
2020-04-10 10:16:38 +02:00
let node = mutation.target.querySelector(chat_item_class);
2020-04-09 18:16:14 +02:00
renderMath(node);
}
2020-04-09 18:25:05 +02:00
2020-04-09 14:31:27 +02:00
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
for(let node of mutation.addedNodes) {
2020-04-10 10:16:38 +02:00
node = node.querySelector(chat_item_class);
2020-04-09 18:16:14 +02:00
renderMath(node);
2020-04-09 14:31:27 +02:00
}
}
}
};
2020-04-09 16:46:59 +02:00
const observer = new MutationObserver(callback);
observer.observe(chat_elem, { attributes: true, childList: true, subtree: true });
2020-04-09 14:31:27 +02:00
return observer;
}
2020-04-09 18:16:14 +02:00
const header = document.querySelector('title');
2020-04-09 20:37:57 +02:00
// start listening
let chat_observer = listen_on_chat_element();
2020-04-09 16:46:59 +02:00
// when changing the chat room, we have to create a new listener
2020-04-09 14:31:27 +02:00
function change_chat_element(mutationsList, observer) {
if (chat_observer) {
chat_observer.disconnect();
}
chat_observer = listen_on_chat_element();
}
2020-04-09 16:46:59 +02:00
// start listening on the header as well
2020-04-09 14:31:27 +02:00
const header_obs = new MutationObserver(change_chat_element)
2020-04-09 16:46:59 +02:00
header_obs.observe(header, { attributes: true, childList: true, subtree: true });
2020-04-09 14:31:27 +02:00
}
2020-04-09 16:46:59 +02:00
// a clever hack to check if riot has been loaded yet
2020-04-09 14:31:27 +02:00
function wait_for_matrix() {
if(!('matrixChat' in window.wrappedJSObject
2020-04-10 10:16:38 +02:00
&& window.wrappedJSObject.matrixChat.firstSyncComplete
&& document.querySelector(chat_class)))
2020-04-09 14:31:27 +02:00
return setTimeout(wait_for_matrix, 500);
init();
}
2020-04-10 10:16:38 +02:00
// detect Riot
let app_name_meta = document.head.querySelector('meta[name="application-name"]');
2020-07-19 18:27:22 +02:00
if (app_name_meta && (app_name_meta.content === 'Riot' || app_name_meta.content === 'Element'))
2020-04-10 10:16:38 +02:00
wait_for_matrix();
2020-04-09 14:31:27 +02:00
})();