Advertisement
Guest User

Untitled

a guest
Jul 23rd, 2019
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.76 KB | None | 0 0
  1. import { uniq, reduce, map, filter, debounce, sortBy, difference } from 'lodash';
  2.  
  3. /**
  4. * Watches for new stylesheets for a period of time, returns a unique list of
  5. * pattern match captures from CSS selectors. Designed to handle a single
  6. * capture group per match, so the resulting array of matches will always be
  7. * strings. The observer is a singleton, callers should pass callbacks that will
  8. * be called when new matches are found. Uses `MutationObserver` to watch for
  9. * stylesheets in the document head. Accepts RegExp `pattern` and an options
  10. * hash for `debounceLength`/`lifespan` in milliseconds, defaulting to 5000 and
  11. * 20000 respectively, and `matchIndex`, defaulting to 1.
  12. *
  13. * Designed to detect CodeMirror themes by checking for a telltale selector
  14. * across all stylesheets and parsing the unique theme name from the selector.
  15. * Note that I ultimately never used it, as observing and processing style
  16. * changes is costly for performance, and the potential for problems wasn't
  17. * worth it.
  18. *
  19. * Regexp for parsing CodeMirror themes in case its useful:
  20. * /^\.cm-s-([\w-]+)\.CodeMirror$/
  21. *
  22. * To use with a React app, call **once per component** that requires the data:
  23. *
  24. * ```js
  25. * componentDidMount() {
  26. * const cb = themes => this.setState({ themes });
  27. * const pattern = /^\.cm-s-([\w-]+)\.CodeMirror$/;
  28. * observeStyles(cb, pattern);
  29. * }
  30. *
  31. * Once the observer expires (20s from init by default), further calls to
  32. * observeStyles are safe and will do nothing.
  33. */
  34.  
  35. let headObserver;
  36. let matches = [];
  37. const headObserverCallbacks = [];
  38.  
  39. export default function observeStyles(cb, pattern, opts = {}) {
  40. const { debounceLength = 5000, lifespan = 20000, matchIndex = 1 } = opts;
  41. if (headObserver === undefined) {
  42. headObserver = new MutationObserver(debounce(
  43. () => onObserveStyles(pattern),
  44. debounceLength,
  45. { leading: true },
  46. ));
  47. headObserver.observe(document.head, { childList: true });
  48. setTimeout(() => {
  49. headObserver.disconnect();
  50. headObserver = null;
  51. }, lifespan);
  52. } else if (headObserver !== null) {
  53. if (matches.length > 0) {
  54. cb(matches);
  55. }
  56. headObserverCallbacks.push(cb);
  57. } else {
  58. cb(matches);
  59. }
  60. }
  61.  
  62. function onObserveStyles(pattern, matchIndex) {
  63. const parsedMatches = parseMatchesFromStyles(pattern, matchIndex);
  64. if (difference(parsedMatches, matches).length > 0) {
  65. matches = parsedMatches;
  66. headObserverCallbacks.forEach(cb => cb(matches));
  67. }
  68. }
  69.  
  70. function parseMatchesFromStyles(pattern, matchIndex) {
  71. const matches = reduce(document.styleSheets, (acc, { cssRules }) => {
  72. const matches = map(cssRules, ({ selectorText }) => {
  73. return selectorText?.match(pattern)?.[matchIndex];
  74. });
  75. return acc.concat(matches);
  76. }, []);
  77.  
  78. return sortBy(uniq(filter(matches, v => v)));
  79. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement