MarioZ
MarioZ

Reputation: 997

Alternative to get all class names from the current stylesheet

I'm writting a webpage to store and view some css concepts and to serve as a workbech. The idea is to work only in the css file and view the results changing the "main" class with JavaScript. I wrote this little piece to fetch all the classes in the current stylesheet:

let cssRules = document.styleSheets[0].cssRules;
Object.keys(cssRules).map(function(key, index) {
    let needle = /\.\w+/;
    let hay = needle.exec(cssRules[key].cssText);

    if(hay != null) {
        let cssClass = hay[0].replace('.','');
        if(styles.indexOf(cssClass) === -1) {
            styles.push(cssClass);
        }
    }
});

I was wondering if there's any easier way to achieve the same, I dind't find anything and I don't know if I'm reinventing the wheel with this.

Here's my Codepen: https://codepen.io/MarioZ/pen/YrrJQQ

And fiddle:

document.addEventListener('DOMContentLoaded', function() {
	let body = document.getElementsByTagName('body')[0];
	let styles = [];
	let wrap = document.createElement('div');
	let select = document.createElement('select');
// Fetches all classes from current stylesheet
  let cssRules = document.styleSheets[0].cssRules;

	Object.keys(cssRules).map(function(key, index) {
    	let needle = /\.\w+/;
		let hay = needle.exec(cssRules[key].cssText);
		
		if(hay != null) {
			let cssClass = hay[0].replace('.','');
			if(styles.indexOf(cssClass) === -1) {
				styles.push(cssClass);
			}
		}
	});
//
	Object.assign(wrap.style, {
								position: 'fixed',
								width: '100%',
								height: '3em',
								left: '0',
								right: '0',
								bottom: '0',
								'line-height': '3em',
								'text-align': 'center',
								background: '',
								'z-index': '9999',
							});

	Object.assign(select.style, {
								width: '80%',
								height: '2em',
								'font-size': '1.2em',
							});

	body.insertBefore(wrap, body.children[body.children.length-1]);
	wrap.appendChild(select);

	for(i=0; i < styles.length; i++) {
		let option = document.createElement('option');
		option.innerHTML = styles[i];
		option.value = styles[i];
		select.appendChild(option);
	}

	select.addEventListener('change', function(e) {
		body.removeAttribute('class');
		body.setAttribute('class',e.target.value);
	});
	
});
* {
	box-sizing: border-box;
}

html, body {
	width: 100%;
	height: 100%;
	margin: 0;
	padding: 0;
	font-size: 18px;
}

a {
	text-decoration: none;
}

/* Place holder for empty p */
article p:empty:after {
	content: "Spicy jalapeno bacon ipsum dolor amet kevin prosciutto boudin, burgdoggen swine meatball shank biltong turkey cupim shankle bacon flank. Meatloaf biltong burgdoggen alcatra picanha bresaola t-bone tongue ground round pancetta ball tip turkey tri-tip chicken leberkas. Doner rump pancetta leberkas, meatball alcatra salami bresaola pork filet mignon bacon sausage. Capicola cow meatloaf beef ribs shoulder swine sausage. Hamburger andouille kielbasa frankfurter chuck picanha kevin sirloin ground round drumstick t-bone doner venison. Jerky alcatra ball tip andouille. Filet mignon cupim tail, kevin meatloaf jerky bresaola flank turducken meatball brisket tri-tip.";
}

main {
	width: 100%;
	padding: 2em;
}

main article {
	display: none;
}

main article:target {
	display: block;
}

/* 
* Create 1 class for each style
* classes are applied to BODY
*/

.base nav {
	position: relative;
	width: 100%;
	min-height: 3rem;
	font-size: 1em;
	text-align: center;
	background: #dadada;
}

.base nav a {
	line-height: 3rem;
	font-size: 1em;
	font-weight: 800;
	text-align: center;
	vertical-align: middle;
}

.base nav a, .base nav a:not(:last-child):after {
	color: #610000;
}

.base nav a:hover {
	color: #ff0000;
}

.base nav a:not(:last-child):after {
	content: " | ";	
}

/* */

/* 
* Base + Invert colors
*/

.invert {
	background: #000000;
	color: #dadada;
}

.invert nav {
	position: relative;
	width: 100%;
	min-height: 3rem;
	font-size: 1em;
	text-align: center;
	background: #610000;
}

.invert nav a {
	line-height: 3rem;
	font-size: 1em;
	font-weight: 800;
	text-align: center;
	vertical-align: middle;
}

.invert nav a, .invert nav a:not(:last-child):after {
	color: #dadada;
}

.invert nav a:hover {
	color: #000000;
}

.invert nav a:not(:last-child):after {
	content: " | ";	
}

/* */
<html>
<head>
	<title>Css Style Viewer</title>
</head>
<body class="base">

<nav>
	<a href="#a1">Cutlass Isle</a>
	<a href="#a2">Barnacle Bay</a>
	<a href="#a3">Death Curse Port</a>
	<a href="#a4">Black Spot Sanctuary</a>
	<a href="#a5">Marauder Hideout</a>
	<a href="#a6">Reef of Anchors</a>
</nav>

<main>
	<article id="a1"><h2>Cutlass Isle</h2><p></p></article>	
	<article id="a2"><h2>Barnacle Bay</h2><p></p></article>	
	<article id="a3"><h2>Death Curse Port</h2><p></p></article>	
	<article id="a4"><h2>Black Spot Sanctuary</h2><p></p></article>	
	<article id="a5"><h2>Marauder Hideout</h2><p></p></article>	
	<article id="a6"><h2>Reef of Anchors</h2><p></p></article>
</main>

</body>
</html>

Upvotes: 0

Views: 90

Answers (1)

D Lowther
D Lowther

Reputation: 1619

I separated out some of the relevant logic into methods to keep it focused. In the parseRules function you could use array.prototype.filter in place of the more complicated mapping function to screen down your css before it hits the mapper. Then all map is doing is mapping keys to help get the correct css text values.

const actionLoad = function() {
  let body = document.getElementsByTagName('body')[0]
  ,   styles = parseRules(document.styleSheets[0].cssRules);

  buildDropDown(body, styles);
}

const parseRules = rules => {
  return Object.keys(rules).filter(key => /\.\w+/.test(rules[key].cssText))
    .map(index => rules[index].selectorText.replace('.', ''))
}

const buildDropDown = (body, styles) => {
  let wrap = document.createElement('div')
  ,   select = document.createElement('select');

  Object.assign(wrap.style, {
    position: 'fixed',
    width: '100%',
    height: '3em',
    left: '0',
    right: '0',
    bottom: '0',
    'line-height': '3em',
    'text-align': 'center',
    background: '',
    'z-index': '9999',
  });

  Object.assign(select.style, {
    width: '80%',
    height: '2em',
    'font-size': '1.2em',
  });

  body.insertBefore(wrap, body.children[body.children.length-1]);
  wrap.appendChild(select);

  select.addEventListener('change', (e) => {
        body.removeAttribute('class');
        body.setAttribute('class',e.target.value);
    });

  styles.forEach(val => {
    let option = document.createElement('option');
    option.textContent = val;
    option.value = val;
    select.appendChild(option);
  })
}
document.addEventListener('DOMContentLoaded', actionLoad, false);

Steps in the parse

const parseRules = rules => {
  const regExCheck = str => /\.\w+/.test(str);
  let keys = Object.keys(rules)
  ,   filterKeys = keys.filter(key => regExCheck(key));
  ,   final = filterKeys.map(index => {
    let rule = rules[index]
    ,   resultText = rule.selectorText.replace('.','');
    return resultText;
  });
  return final;
};

Upvotes: 1

Related Questions