Skip to content

Commit

Permalink
Add render() helper
Browse files Browse the repository at this point in the history
  • Loading branch information
jsor committed Aug 21, 2018
1 parent 1db8004 commit f81f598
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 0 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
data,
focus,
parents,
render,

// Event
ready,
Expand Down Expand Up @@ -86,6 +87,7 @@ API
* [data()](#data)
* [focus()](#focus)
* [parents()](#parents)
* [render()](#render)
* [Event](#event)
* [ready()](#ready)
* [on()](#on)
Expand Down Expand Up @@ -314,6 +316,30 @@ Returns an array of the element's parent elements.
const parentElements = parents(element);
```

#### render()

```
render(html: string): object
```

Creates and returns DOM element references from a HTML string.

Elements must have a `ref` attribute with the reference name. The value of this
attribute will get mapped to the property name of the returned object.

##### Example

```javascript
const {list, 'list-items': listItems} = render(`
<ul ref="list">
<li ref="list-items[]"></l>
<li ref="list-items[]"></l>
</ul>
`);
```

> Note: The `ref` attributes will be removed from the returned elements.
### Event

#### ready()
Expand Down
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {addClass, hasClass, removeClass} from './src/element/class';
import data from './src/element/data';
import focus from './src/element/focus';
import parents from './src/element/parents';
import render from './src/element/render';

import delegate from './src/event/delegate';
import dispatch from './src/event/dispatch';
Expand Down Expand Up @@ -37,6 +38,7 @@ export {
data,
focus,
parents,
render,

// Event
delegate,
Expand Down
36 changes: 36 additions & 0 deletions src/element/render.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import find from '../query/find';
import fragmentContainer from '../util/fragment-container';

export default function render(html) {
const container = fragmentContainer(html);

const result = find('[ref]', container).reduce(
(result, element) => {
const [, refName, isArray] = element
.getAttribute('ref')
.trim()
.match(/(.*?)(\[\])?$/);

element.removeAttribute('ref');

if (!isArray) {
result[refName] = element;

return result;
}

result[refName] = Array.isArray(result[refName]) ? result[refName] : [];
result[refName].push(element);

return result;
},
{}
);

// Detach all elements from the container
[].slice.call(container.childNodes).forEach(childNode => {
container.removeChild(childNode);
});

return result;
}
140 changes: 140 additions & 0 deletions test/element/render.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import {render} from '../..';

describe('render()', () => {
it('creates references from a string', () => {
const {article, section} = render('<article ref="article"><section ref="section"><p>foo</p><p>bar</p></section></article>');

assert.instanceOf(article, Element);
assert.isNull(article.parentElement);
assert.equal(article.outerHTML, '<article><section><p>foo</p><p>bar</p></section></article>');

assert.instanceOf(section, Element);
assert.isNull(section.parentElement.parentElement);
assert.equal(section.parentElement, article);
});

it('creates references from a string (single tag)', () => {
const {node} = render('<span ref="node"></span>');

assert.instanceOf(node, Element);
assert.equal(node.tagName.toLowerCase(), 'span');
});

it('creates references from a string (self-closing tag)', () => {
const {node} = render('<span ref="node"/>');

assert.instanceOf(node, Element);
assert.equal(node.tagName.toLowerCase(), 'span');
});

it('creates references for multiple root element', () => {
const {node1, node2} = render('<p ref="node1"></p><span ref="node2"/>');

assert.equal(node1.tagName.toLowerCase(), 'p');
assert.equal(node2.tagName.toLowerCase(), 'span');
});

it('creates array references', () => {
const {'list-items': listItems} = render('<ul><li ref="list-items[]"></li><li ref="list-items[]"></li></ul>');

assert.instanceOf(listItems, Array);
assert.equal(listItems.length, 2);
assert.equal(listItems[0].tagName.toLowerCase(), 'li');
assert.equal(listItems[1].tagName.toLowerCase(), 'li');

assert.equal(listItems[0].nextElementSibling, listItems[1]);

assert.equal(listItems[0].parentElement.tagName.toLowerCase(), 'ul');
assert.equal(listItems[1].parentElement.tagName.toLowerCase(), 'ul');

assert.isNull(listItems[0].parentElement.parentElement);
assert.isNull(listItems[1].parentElement.parentElement);
});

// Special nodes which require specific parents
// See: https://github.com/jquery/jquery/blob/c9aae3565edc840961ecbeee77fb0cb367c46702/src/manipulation/wrapMap.js

it('renders a <legend/> node from a string', () => {
const {node} = render('<legend ref="node"/>');

assert.equal(node.tagName.toLowerCase(), 'legend');
assert.isNull(node.parentNode);
});

it('renders a <option/> node from a string', () => {
const {node} = render('<option ref="node"/>');

assert.equal(node.tagName.toLowerCase(), 'option');
assert.isNull(node.parentNode);
});

it('renders a <optgroup/> node from a string', () => {
const {node} = render('<optgroup ref="node"/>');

assert.equal(node.tagName.toLowerCase(), 'optgroup');
assert.isNull(node.parentNode);
});

it('renders a <thead/> node from a string', () => {
const {node} = render('<thead ref="node"/>');

assert.equal(node.tagName.toLowerCase(), 'thead');
assert.isNull(node.parentNode);
});

it('renders a <tbody/> node from a string', () => {
const {node} = render('<tbody ref="node"/>');

assert.equal(node.tagName.toLowerCase(), 'tbody');
assert.isNull(node.parentNode);
});

it('renders a <tfoot/> node from a string', () => {
const {node} = render('<tfoot ref="node"/>');

assert.equal(node.tagName.toLowerCase(), 'tfoot');
assert.isNull(node.parentNode);
});

it('renders a <colgroup/> node from a string', () => {
const {node} = render('<colgroup ref="node"/>');

assert.equal(node.tagName.toLowerCase(), 'colgroup');
assert.isNull(node.parentNode);
});

it('renders a <col/> node from a string', () => {
const {node} = render('<col ref="node"/>');

assert.equal(node.tagName.toLowerCase(), 'col');
assert.isNull(node.parentNode);
});

it('renders a <caption/> node from a string', () => {
const {node} = render('<caption ref="node"/>');

assert.equal(node.tagName.toLowerCase(), 'caption');
assert.isNull(node.parentNode);
});

it('renders a <tr/> node from a string', () => {
const {node} = render('<tr ref="node"/>');

assert.equal(node.tagName.toLowerCase(), 'tr');
assert.isNull(node.parentNode);
});

it('renders a <th/> node from a string', () => {
const {node} = render('<th ref="node"/>');

assert.equal(node.tagName.toLowerCase(), 'th');
assert.isNull(node.parentNode);
});

it('renders a <td/> node from a string', () => {
const {node} = render('<td ref="node"/>');

assert.equal(node.tagName.toLowerCase(), 'td');
assert.isNull(node.parentNode);
});
});

0 comments on commit f81f598

Please sign in to comment.