Last active
August 23, 2023 12:41
-
-
Save marcustyphoon/eeb1f81c6c408f73d89da51ab9d36716 to your computer and use it in GitHub Desktop.
userscript to translate the tumblr css map classes automatically
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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