Skip to content

Instantly share code, notes, and snippets.

@rcherny
Last active August 20, 2021 17:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rcherny/9e82ec215e3e20867c1137d56bf487fc to your computer and use it in GitHub Desktop.
Save rcherny/9e82ec215e3e20867c1137d56bf487fc to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name StyledTags
// @namespace http://tampermonkey.net/
// @version 0.2
// @description try to take over the world!
// @author You
// @match https://*.workflowy.com/*
// @icon https://www.google.com/s2/favicons?domain=workflowy.com
// @grant none
// ==/UserScript==
/**
* https://gist.github.com/rcherny/9e82ec215e3e20867c1137d56bf487fc
* StyledTagging v.2 (αlpha or, even βeta)
* @todo apply move to github repo
* @todo apply eslint
* @todo apply prettier
* @todo test much, much, much more
* @todo be certain it is applying styles only on appropriate mutated nodes
*
* 2021-08-20
*
*/
(() => {
const DEBUG = true;
const TIMEOUT = 45000;
const logger = (enable = true) => {
const method = 'log';
if (enable) {
// eslint-disable-next-line no-console
return console[method].bind(console);
}
return () => {}
}
const log = logger(DEBUG);
const vlog = logger(true);
const SEL = {
ROOT: 'div.page.active',
SUFFIX: '-proj',
PROJECT: '.project',
PCONTAINER: '.pageContainer',
TAGPATH: 'span > .contentTagText'
}
const {
ROOT, SUFFIX, PROJECT, PCONTAINER, TAGPATH
} = SEL;
const debounce = (callback, delay = 250) => {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId)
timeoutId = setTimeout(() => {
timeoutId = null;
callback(...args);
}, delay)
}
}
let StylableTagsCounter = 1;
const findAll = select => {
return document.querySelectorAll(select);
}
const removeClasses = select => {
const result = findAll(select);
result.forEach(el => {
el.classList.forEach(i => {
if (i.indexOf(SUFFIX) !== -1) {
el.classList.remove(i);
}
})
})
}
const addClasses = (select, parentItem) => {
const result = findAll(select);
result.forEach(el => {
const itemText = el.textContent.toLowerCase();
const parentProject = el.closest(parentItem);
parentProject.classList.add(itemText + SUFFIX);
});
}
const styleTags = () => {
// eslint-disable-next-line no-plusplus
StylableTagsCounter++;
if( StylableTagsCounter >= 3){
removeClasses(PROJECT);
removeClasses(PCONTAINER);
StylableTagsCounter = 0;
}
addClasses(TAGPATH, PROJECT);
}
const workChange = debounce(m => {
log('registered change', m && m.type ? m.type : 'init')
styleTags()
}, 250)
let wftarget;
const wfobserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
vlog('Observer: ', mutation.type);
switch (mutation.type) {
case 'childList':
case 'characterData':
case 'subtree':
workChange(mutation)
break;
default:
return true;
}
});
});
const pageLoad = () => {
const complete = document.readyState;
return complete === 'complete'
? Promise.resolve()
: new Promise(resolve => window.addEventListener('load', resolve));
};
const rootNode = () => {
return new Promise((resolve, reject) => {
let n, h, i;
i = setInterval(() => {
n = document.querySelector(ROOT);
// vlog('n:', n);
if (!!n) {
clearInterval(i);
clearTimeout(h);
resolve(n);
};
}, 500)
h = setTimeout(() => {
clearInterval(i);
vlog('Time out fired!');
reject(false)
}, TIMEOUT);
});
};
const wfconfig = { attributes: false, childList: true, characterData: true, subtree: true };
pageLoad().then(() => {
const target = rootNode();
console.log(target);
target.then((t) => {
wftarget = t;
vlog-('User Script:', wftarget, wfconfig);
wfobserver.observe(wftarget, wfconfig);
workChange();
}).catch(e => {
vlog('User script failed to run: node not found.', e);
vlog('Timed out:', TIMEOUT, document.querySelector(ROOT));
})
});
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment