Skip to content

Instantly share code, notes, and snippets.

@marcustyphoon
Last active August 23, 2023 12:41
Show Gist options
  • Save marcustyphoon/eeb1f81c6c408f73d89da51ab9d36716 to your computer and use it in GitHub Desktop.
Save marcustyphoon/eeb1f81c6c408f73d89da51ab9d36716 to your computer and use it in GitHub Desktop.
userscript to translate the tumblr css map classes automatically
// ==UserScript==
// @name Tumblr CSS Map
// @namespace gist.github.com/marcustyphoon
// @version 0.5
// @description translate the tumblr css map automatically
// @author marcustyphoon
// @include https://www.tumblr.com/*
// @grant GM_registerMenuCommand
// @noframes
// ==/UserScript==
const options = {
// Choose how you would like each translated class formatted.
// Yes, emoji are supported! Avoid punctuation and whitespace.
format: (originalCss, mappedCss) => 'β“£' + mappedCss,
// Select true to insert translations as a data attribute instead of as classes.
useDataAttributes: false,
// In class mode, this class gets added to almost every DOM element.
// It's nice to make it short for the π’Άπ‘’π“ˆπ“‰π’½π‘’π“‰π’Ύπ’Έ.
markerClass: 'β€’',
// Don't log to the console
silent: true,
};
/* globals tumblr, GM_registerMenuCommand */
(async function () {
'use strict';
let retries = 0;
while (
retries++ < 1000 &&
(typeof tumblr === 'undefined' || typeof tumblr.getCssMap === 'undefined')
) {
await new Promise((resolve) => setTimeout(resolve));
}
const cssMap = await tumblr.getCssMap();
const reverseCssMap = {};
for (const [key, values] of Object.entries(cssMap)) {
for (const value of values) {
reverseCssMap[value] = key;
}
}
const selector = options.useDataAttributes
? '[class]:not([data-css])'
: `[class]:not(.${options.markerClass})`;
const translateCss = () => {
const timer = Date.now();
const elements = document.body.querySelectorAll(selector);
for (const element of elements) {
const classes = [];
for (const css of element.classList.values()) {
const mappedCss = reverseCssMap[css];
if (mappedCss) {
classes.push(options.format(css, mappedCss));
}
}
if (options.useDataAttributes) {
element.dataset.css = classes.join(' ');
} else {
element.classList.add(options.markerClass, ...classes);
}
}
!options.silent &&
console.log(
`added css translation to ${elements.length} elements in ${Date.now() - timer} ms`,
);
};
const throttle = (func) => {
let running = false;
return (...args) => {
if (!running) {
running = true;
requestAnimationFrame(() => {
running = false;
func(...args);
});
}
};
};
const throttledtranslateCss = throttle(translateCss);
throttledtranslateCss();
const cssObserver = new MutationObserver(throttledtranslateCss);
cssObserver.observe(document.body, {
childList: true,
subtree: true,
});
GM_registerMenuCommand('Stop CSS observer', () => {
cssObserver.disconnect();
console.log('css observer stopped');
});
GM_registerMenuCommand('Start CSS observer', () => {
cssObserver.observe(document.body, {
childList: true,
subtree: true,
});
console.log('css observer started');
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment