Skip to content

Commit

Permalink
more to es6
Browse files Browse the repository at this point in the history
  • Loading branch information
AvraamMavridis committed Apr 10, 2016
1 parent 311bd3e commit decac65
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 147 deletions.
4 changes: 4 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,9 @@
"browser": true,
"node": true
},
"globals": {
"describe": true,
"it": true
},
"extends": "airbnb/base"
}
18 changes: 13 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
"name": "unique-selector",
"version": "0.0.5",
"description": "Given a DOM node, return a unique CSS selector matching only that element",
"main": "index.js",
"main": "./lib/index.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "npm run compile && mocha --compilers js:babel-register --require babel-polyfill",
"build": "webpack -p --config --progress --colors",
"test": "npm run compile && mocha --ignore-leaks --compilers js:babel-register --require babel-polyfill",
"compile": "babel --presets es2015,stage-0,stage-1,stage-2 --require babel-polyfill -d lib/ src/",
"prepublish": "npm run compile",
"watch": "npm-scripts-watcher"
Expand All @@ -29,23 +30,30 @@
"event"
],
"author": "Eric Clemmons <[email protected]>",
"contributors":[{
"contributors": [
{
"name": "Avraam Mavridis",
"email": "[email protected]"
}],
}
],
"license": "MIT",
"devDependencies": {
"babel-cli": "^6.1.18",
"babel-core": "^6.1.18",
"babel-preset-es2015": "^6.1.18",
"babel-preset-stage-0": "^6.1.18",
"babel-register": "^6.3.13",
"chai": "^3.5.0",
"component": "~0.10.1",
"eslint": "^2.6.0",
"eslint-config-airbnb": "^6.2.0",
"eslint-config-airbnb-lite": "^1.0.4",
"eslint-plugin-react": "^4.2.3",
"jquery": "^2.2.3",
"jsdom": "^8.3.0",
"mocha": "~1.7.4",
"mocha-phantomjs": "~1.1.1"
"mocha-jsdom": "^1.1.0",
"mocha-phantomjs": "~1.1.1",
"open-browser-webpack-plugin": "0.0.2"
}
}
8 changes: 4 additions & 4 deletions src/getAttributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
export function getAttributes( el, attributesToIgnore = ['id', 'class', 'length'] )
{
const { attributes } = el;
const attributeKeys = Object.keys( attributes );
const attrs = [ ...attributes ];

return attributeKeys.reduce( ( sum, next ) =>
return attrs.reduce( ( sum, next ) =>
{
if ( ! ( this.attributesToIgnore.indexOf( next ) > -1 ) )
if ( ! ( attributesToIgnore.indexOf( next.nodeName ) > -1 ) )
{
sum.push( `[${next}=${attributes[ next ]}]` );
sum.push( `[${next.nodeName}="${next.value}"]` );
}
return sum;
}, [] );
Expand Down
4 changes: 2 additions & 2 deletions src/getClasses.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @pararm { Element } el
* @return { Array }
*/
export function getClassNames( el )
export function getClasses( el )
{
let classNames;

Expand Down Expand Up @@ -38,6 +38,6 @@ export function getClassNames( el )
*/
export function getClassSelectors( el )
{
const classList = getClassNames( el );
const classList = getClasses( el ).filter( Boolean );
return classList.map( cl => `.${cl}` );
}
32 changes: 21 additions & 11 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Expose `unique`
*/

import { getClassNames } from './getClassNames';
import { getClassSelectors } from './getClasses';
import { getAttributes } from './getAttributes';
import { getNthChild } from './getNthChild';
import { getTag } from './getTag';
Expand All @@ -15,15 +15,14 @@ import { getParents } from './getParents';
* @param { Object } element
* @return { Object }
*/
function getAllSelectors( el, options )
function getAllSelectors( el, selectors )
{
const { selectors } = options;
const funcs =
{
'Tag' : getTag,
'NthChild' : getNthChild,
'Attributes' : getAttributes,
'Class' : getClassNames,
'Class' : getClassSelectors,
};

return selectors.reduce( ( res, next ) =>
Expand All @@ -41,6 +40,7 @@ function getAllSelectors( el, options )
*/
function testUniqueness( element, selector )
{
console.log( selector );
const { parentNode } = element;
const elements = parentNode.querySelectorAll( selector );
return elements.length === 1 && elements[ 0 ] === element;
Expand All @@ -56,6 +56,7 @@ function testUniqueness( element, selector )
function getUniqueCombination( element, items, tag )
{
const combinations = getCombinations( items );
console.log( '#####', combinations, items );
const uniqCombinations = combinations.filter( testUniqueness.bind( this, element ) );
if( uniqCombinations.length ) return uniqCombinations[ 0 ];

Expand All @@ -69,15 +70,19 @@ function getUniqueCombination( element, items, tag )
return null;
}


function getUniqueSelector( el, options=['Class', 'Tag', 'NthChild'] )
/**
* Returns a uniqueSelector based on the passed options
* @param { DOM } element
* @param { Array } options
* @return { String }
*/
function getUniqueSelector( el, selectorTypes=['Class', 'Attributes', 'Tag', 'NthChild'] )
{
let foundSelector;

const elementSelectors = getAllSelectors( el );
const { selectors } = options;
const elementSelectors = getAllSelectors( el, selectorTypes );

for( let selectorType of selectors )
for( let selectorType of selectorTypes )
{
const { Tag, Class : Classes, Attributes, NthChild } = elementSelectors;
switch( selectorType )
Expand Down Expand Up @@ -125,6 +130,9 @@ function getUniqueSelector( el, options=['Class', 'Tag', 'NthChild'] )
return '*';
}

/**
* Returns all the possible selector compinations
*/
function getCombinations( items )
{
items = items ? items : [];
Expand Down Expand Up @@ -159,13 +167,15 @@ function getCombinations( items )
* @api private
*/

function unique( el )
export default function unique( el, options={} )
{
const { selectorTypes=['Class', 'Attributes', 'Tag', 'NthChild'] } = options;
const allSelectors = [];
const parents = getParents( el );

for( let elem of parents )
{
const selector = getUniqueSelector( elem );
const selector = getUniqueSelector( elem, selectorTypes );
if( Boolean( selector ) )
{
allSelectors.push( selector );
Expand Down
5 changes: 5 additions & 0 deletions static/bundle.js

Large diffs are not rendered by default.

72 changes: 0 additions & 72 deletions test/index.html
Original file line number Diff line number Diff line change
@@ -1,72 +0,0 @@
<!DOCTYPE html>

<html>
<head>
<title>unique-selector tests</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="../node_modules/mocha/mocha.css" />
<script src="../node_modules/mocha/mocha.js"></script>
<script>
mocha.setup('bdd');
</script>
</head>
<body>
<div id="mocha"></div>

<div id="fixture">
<h3>Test Fixture <small>(for Mocha)</small></h3>

<p>
Lorem <em>ipsum</em> dolor sit amet, consectetur adipisicing elit.
</p>

<div class=" classnames with extra space ">
<span></span>
</div>

<ul id="nav">
<li class="first item">Item 1</li>
<li class="collapsed item">
Item 2

<ul id="nested">
<li class="child"><img alt="Some Title" /></li>
</ul>
</li>
<li class="last collapsed item">Item 3</li>
</ul>

<form>
<select name="state">
<option value="NM">New Mexico</option>
<option value="NY">New York</option>
<option value="TX" selected>Texas</option>
</select>

<p>
Do you have a computer?

<label>
<input type="radio" name="computer" value="1" checked />&nbsp;Yes
</label>

<label>
<input type="radio" name="computer" value="0" />&nbsp;No
</label>
</p>
</form>
</div>

<script src="../build/build.js"></script>
<script src="unique-selector.js"></script>
<script>
var cloud = require('visionmedia-mocha-cloud/client');

if (window.mochaPhantomJS) {
mochaPhantomJS.run()
} else {
cloud(mocha.run());
}
</script>
</body>
</html>
89 changes: 36 additions & 53 deletions test/unique-selector.js
Original file line number Diff line number Diff line change
@@ -1,60 +1,43 @@
var unique = '../lib';
const jsdom = require( 'mocha-jsdom' );
const expect = require( 'chai' ).expect;
import unique from '../src';

function assert(expr, msg) {
if (!expr) throw new Error(typeof msg === undefined ? 'failed' : msg);
}
const $ = require( 'jquery' )( require( 'jsdom' ).jsdom().defaultView );

describe('unique-selector', function() {
describe('with undefined', function() {
it('should return a TypeError', function() {
try {
unique();
assert(false);
} catch (e) {
assert(e instanceof TypeError);
}
});
});
describe( 'Unique Selector Tests', () =>
{
jsdom( { skipWindowCheck : true } );

describe('with Object', function() {
it('should return a TypeError', function() {
try {
unique({});
assert(false);
} catch (e) {
assert(e instanceof TypeError);
}
});
});
it( 'Class Selector Test', () =>
{
$( 'body' ).append( '<div class="something">TEST</div>' );
const findNode = $( 'body' ).find( '.something' ).get( 0 );
const uniqueSelector = unique( findNode );
expect( uniqueSelector ).to.equal( '.something' );
} );

var selectors = {
// Selector: expected
'HTML > BODY': 'html > body',
'HTML > BODY > DIV#fixture': '#fixture',
'HTML > BODY > DIV#fixture > H3 > SMALL': '#fixture > h3 > small',
'HTML > BODY > DIV#fixture > UL#nav > LI:nth-child(1)': '#nav > li.first.item',
'HTML > BODY > DIV#fixture > UL#nav > LI:nth-child(2)': '#nav > li.collapsed.item:nth-child(2)',
'HTML > BODY > DIV#fixture > UL#nav > LI:nth-child(3)': '#nav > li.last.collapsed.item',
'HTML > BODY > DIV#fixture > UL#nav > LI.item > UL#nested > LI.child > IMG': '#nested > li.child > img[alt="Some Title"]',
'HTML > BODY > DIV#fixture > FORM > SELECT > OPTION[selected]': '#fixture > form > select[name="state"] > option[value="TX"]',
'HTML > BODY > DIV#fixture > FORM > P > LABEL > INPUT[checked]': '#fixture > form > p > label > input[name="computer"][value="1"]',
'HTML > BODY > DIV#fixture > DIV.classnames.with.extra.space > SPAN': '#fixture > div.classnames.with.extra.space > span'
};
it( 'Nth Child', () =>
{
$( 'body' ).append( '<div class="something">TEST</div><div class="something">TEST</div>' );
const findNode = $( 'body' ).find( '.something' ).get( 0 );
const uniqueSelector = unique( findNode );
expect( uniqueSelector ).to.equal( 'body > :nth-child(1)' );
} );

for (var selector in selectors) {
describe('with ' + selector, function() {
var expected = selectors[selector];
var match = selector ? document.querySelector(selector): undefined;
var matches = selector ? document.querySelectorAll(selector) : undefined;
var actual = match ? unique(match) : undefined;
it( 'Attributes', () =>
{
$( 'body' ).append( '<div class="something">TEST</div><div class="else" lol="5">TEST</div>' );
const findNode = $( 'body' ).find( '.else' ).get( 0 );
const uniqueSelector = unique( findNode, { selectorTypes : [ 'Attributes' ] } );
expect( uniqueSelector ).to.equal( '[lol="5"]' );
} );

it('should have only 1 match', function() {
assert(1 === matches.length, matches.length + ' matches');
});
it( 'Nth Child', () =>
{
$( 'body' ).append( '<div class="something2"></div><div class="something2"></div>' );
const findNode = $( 'body' ).find( '.something2' ).get( 0 );
const uniqueSelector = unique( findNode );
expect( uniqueSelector ).to.equal( 'body > :nth-child(1)' );
} );

it('should return `' + expected + '`', function() {
assert(expected === actual, actual);
});
});
}
});
} );

0 comments on commit decac65

Please sign in to comment.