Калькулятор специфичности

by Евгений

HTML

<div class="main">
		<h1>Specificity Calculator</h1>
		<p class="intro">Калькулятор <a href="http://www.w3.org/TR/css3-selectors/#specificity" target="_blank">специфичности CSS</a> от <a href="http://specificity.keegan.st/">Keegan Street</a>. Измените или вставьте селекторы в поля ниже.</p>
		<div id="items" class="items">
			<div class="item is-small transition-all">
				<textarea type="text" class="input">ul#nav li.active a</textarea>
				<div class="selector"><span class="type-c">ul</span><span class="type-a">#nav</span> <span class="type-c">li</span><span class="type-b">.active</span> <span class="type-c">a</span></div>
				<div class="specificity">
					<span class="type-z">0</span>
					<span class="type-a">1</span>
					<span class="type-b">1</span>
					<span class="type-c">3</span>
				</div>
				<div class="legend">
          <span class="type-z">Стили в атрибуте <code>style</code></span>
					<span class="type-a">ID</span>
					<span class="type-b">Классы, псевдоклассы</span>
					<span class="type-c">Элементы, псевдоэлементы</span>
				</div>
				<a href="#" class="duplicate button">Клонировать</a>
			</div>
		</div>
	</main>
	<div class="menu">
		<a href="#" class="sort button">Сортировать по специфичности</a>
	</div>
	
	<div class="offscreen-container"><div id="offscreen"></div></div>

CSS

/*
 * The colour theme for Specificity Calculator is from http://ethanschoonover.com/solarized
 */

body {
	background: #FDF6E3;
	color: #657B83;
}

h1 {
	font-size: 40px;
	line-height: 40px;
	margin: 25px 0 5px;
	color: #CB4B16;
	letter-spacing: -1px;
}

p {
	line-height: 1.5em;
}

a {
	color: #6C71C4;
}

code {
	background-color: transparentize(white,.6);
	border: 1px solid #CCCCCC;
	-webkit-border-radius: 3px;
	border-radius: 3px;
	padding: 0 5px;
}

.intro {
	font-style: italic;
	margin-top: 0;
}

.footer {
	margin-bottom: 60px;
}

.main {
	width: 680px;
	margin: 0 auto;
}

/* Items */

#items {
	width: 680px;
	min-height: 536px;
	position: relative;
}

.item {
	background: #FFF;
	padding: 20px 20px 10px;
	width: 640px;
	margin-bottom: 20px;
	-webkit-box-shadow: 0px 0px 10px 0px #D5CEBB;
	box-shadow: 0px 0px 10px 0px #D5CEBB;
	-webkit-border-radius: 3px;
	border-radius: 3px;
	overflow: hidden;
	position: relative;
	opacity: 1;
}

.transition-all {
	-webkit-transition: all 0.2s ease;
	-moz-transition: all 0.2s ease;
	-ms-transition: all 0.2s ease;
	-o-transition: all 0.2s ease;
	transition: all 0.2s ease;
}

.is-small {
	-webkit-transform: scale(0.6);
	-moz-transform: scale(0.6);
	-ms-transform: scale(0.6);
	-o-transform: scale(0.6);
	transform: scale(0.6);
	opacity: 0;
}

	.input,
	.selector {
		font-size: 28px;
		line-height: 36px;
		font-family: monospace, serif;
		_font-family: 'courier new', monospace;
	}

	.input {
		width: 630px;
		height: 36px;
		position: absolute;
		top: 20px;
		left: 20px;
		padding: 3px 5px;
		border: none;
		background: none;
		color: #FFF;
		resize: none;
		outline: none;
		overflow: hidden;
	}

		.input:focus,
		.input:active {
			-moz-box-shadow: 0 0 10px #00171D;
			-webkit-box-shadow: 0 0 10px #00171D;
			box-shadow: 0 0 10px #00171D;
		}

	.selector {
		width: 630px;
		min-height: 36px;
		padding: 3px 5px;
		background: #002B36;
		white-space: pre-wrap;
	}

	.specificity {
		margin: 20px 0 0;
		color: #FFF;
		font-size:...

JavaScript

/**
 * Calculates the specificity of CSS selectors
 * http://www.w3.org/TR/css3-selectors/#specificity
 *
 * Returns an array of objects with the following properties:
 *  - selector: the input
 *  - specificity: e.g. 0,1,0,0
 *  - parts: array with details about each part of the selector that counts towards the specificity
 */
var SPECIFICITY = (function() {
	var calculate,
		calculateSingle;

	calculate = function(input) {
		var selectors,
			selector,
			i,
			len,
			results = [];

		// Separate input by commas
		selectors = input.split(',');

		for (i = 0, len = selectors.length; i < len; i += 1) {
			selector = selectors[i];
			if (selector.length > 0) {
				results.push(calculateSingle(selector));
			}
		}

		return results;
	};

	// Calculate the specificity for a selector by dividing it into simple selectors and counting them
	calculateSingle = function(input) {
		var selector = input,
			findMatch,
			typeCount = {
				'a': 0,
				'b': 0,
				'c': 0
			},
			parts = [],
			// The following regular expressions assume that selectors matching the preceding regular expressions have been removed
			attributeRegex = /(\[[^\]]+\])/g,
			idRegex = /(#[^\s\+>~\.\[:]+)/g,
			classRegex = /(\.[^\s\+>~\.\[:]+)/g,
			pseudoElementRegex = /(::[^\s\+>~\.\[:]+|:first-line|:first-letter|:before|:after)/gi,
			// A regex for pseudo classes with brackets - :nth-child(), :nth-last-child(), :nth-of-type(), :nth-last-type(), :lang()
			pseudoClassWithBracketsRegex = /(:[\w-]+\([^\)]*\))/gi,
			// A regex for other pseudo classes, which don't have brackets
			pseudoClassRegex = /(:[^\s\+>~\.\[:]+)/g,
			elementRegex = /([^\s\+>~\.\[:]+)/g;

		// Find matches for a regular expression in a string and push their details to parts
		// Type is "a" for IDs, "b" for classes, attributes and pseudo-classes and "c" for elements and pseudo-elements
		findMatch = function(regex, type) {
			var matches, i, len, match, index, length;
			if (regex.test(selector)) {
				matches =...