Skip to content

Commit 6a4da4e

Browse files
committed
Change API
1 parent ec801ae commit 6a4da4e

File tree

4 files changed

+136
-104
lines changed

4 files changed

+136
-104
lines changed

src/accordion.js

+11-36
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,24 @@
1+
import AccordionItem from './lib/accordion-item.js';
2+
13
export default class Accordion {
24
constructor (window) {
3-
const container = window.document.querySelector('[data-accordion]');
4-
if (container) {
5-
this.container = container;
5+
const element = window.document.querySelector('[data-accordion]');
6+
if (element) {
7+
this.items = [].map.call(element.children, child => new AccordionItem(child));
68
} else {
79
throw new Error('Can\'t find data-accordion element.');
810
}
9-
this.initialize();
1011
}
1112

12-
children() {
13-
return this.container.children;
13+
item(index) {
14+
return this.items[index];
1415
}
1516

16-
initialize() {
17-
[].forEach.call(this.container.children, (child) => {
18-
if (!child.hasAttribute('data-accordion-closed') && !child.hasAttribute('data-accordion-open')) {
19-
this.collapse(child);
20-
}
21-
});
17+
collapseAll() {
18+
[].forEach.call(this.items, item => item.collapse());
2219
}
2320

24-
collapse(item) {
25-
const itemBody = item.querySelector('*[data-accordion-item-body]');
26-
if (!item.hasAttribute('data-accordion-closed')) {
27-
item.setAttribute('data-accordion-closed', true);
28-
if (item.hasAttribute('data-accordion-open')) {
29-
item.removeAttribute('data-accordion-open');
30-
}
31-
if (itemBody) {
32-
itemBody.style.display = 'none';
33-
}
34-
}
35-
}
36-
37-
expand(item) {
38-
const itemBody = item.querySelector('*[data-accordion-item-body]');
39-
if (!item.hasAttribute('data-accordion-open')) {
40-
item.setAttribute('data-accordion-open', true);
41-
if (item.hasAttribute('data-accordion-closed')) {
42-
item.removeAttribute('data-accordion-closed');
43-
}
44-
if (itemBody) {
45-
itemBody.style.display = null;
46-
}
47-
}
21+
expandAll() {
22+
[].forEach.call(this.items, item => item.expand());
4823
}
4924
}

src/accordion.spec.js

+8-68
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import tap from 'tap';
22
import {jsdom} from 'jsdom';
33
import Accordion from './accordion';
44

5-
tap.test('The accordion module should exist', (t) => {
5+
tap.test('Accordion exists', (t) => {
66
t.ok(Accordion);
77
t.end();
88
});
@@ -11,82 +11,22 @@ tap.test('An accordion module instance', (t) => {
1111
const markup = `<div data-accordion></div>`;
1212
const window = jsdom(markup).defaultView;
1313
const accordion = new Accordion(window);
14-
t.ok(accordion.container.hasAttribute('data-accordion'), 'container property is defined');
15-
t.ok(accordion.container.hasAttribute('data-accordion'), 'container property contains a data-accordion element');
14+
t.equal(accordion.items.length, 0, 'container property is defined');
1615
t.end();
1716
});
1817

19-
tap.test('Accordion module instance children method', (t) => {
18+
tap.test('#item method', t => {
2019
const markup = `
2120
<div data-accordion>
2221
<div data-accordion-item></div>
22+
<div data-accordion-item></div>
23+
<div data-accordion-item></div>
24+
<div data-accordion-item></div>
25+
<div data-accordion-item></div>
2326
</div>
2427
`;
2528
const window = jsdom(markup).defaultView;
2629
const accordion = new Accordion(window);
27-
const children = window.document.querySelector('[data-accordion]').children;
28-
t.ok(accordion.children, 'is defined');
29-
t.ok(accordion.children()[0].hasAttribute('data-accordion-item'), 'returns container children');
30-
t.end();
31-
});
32-
33-
tap.test('Accordion module instance initialize method', (t) => {
34-
const markup = `
35-
<div data-accordion>
36-
<div data-accordion-item>
37-
<div data-accordion-item-body></div>
38-
</div>
39-
</div>
40-
`;
41-
const window = jsdom(markup).defaultView;
42-
const accordionElement = window.document.querySelector('div[data-accordion]');
43-
const accordion = new Accordion(window);
44-
t.ok(accordion.initialize, 'is defined');
45-
accordion.initialize();
46-
t.ok(accordionElement.children[0].hasAttribute('data-accordion-closed'), 'mark accordion items as closed');
47-
t.end();
48-
});
49-
50-
tap.test('Accordion module instance collapse method', (t) => {
51-
const markup = `
52-
<div data-accordion>
53-
<div data-accordion-item>
54-
<div data-accordion-item-body></div>
55-
</div>
56-
<div data-accordion-item data-accordion-open></div>
57-
</div>
58-
`;
59-
const window = jsdom(markup).defaultView;
60-
const accordionItemElements = window.document.querySelectorAll('div[data-accordion-item]');
61-
const itemBody = accordionItemElements[0].querySelector('*[data-accordion-item-body]');
62-
const accordion = new Accordion(window);
63-
t.ok(accordion.collapse, 'is defined');
64-
accordion.collapse(accordionItemElements[0]);
65-
accordion.collapse(accordionItemElements[1]);
66-
t.ok(accordionItemElements[0].hasAttribute('data-accordion-closed'), 'mark accordion item closed');
67-
t.ok(accordionItemElements[1].hasAttribute('data-accordion-closed'), 'mark bodyless accordion item closed');
68-
t.equal(itemBody.style.display, 'none', 'hides accordion item body when present');
69-
t.end();
70-
});
71-
72-
tap.test('Accordion module instance expand method', (t) => {
73-
const markup = `
74-
<div data-accordion>
75-
<div data-accordion-item>
76-
<div data-accordion-item-body style="display: none;"></div>
77-
</div>
78-
<div data-accordion-item data-accordion-open></div>
79-
</div>
80-
`;
81-
const window = jsdom(markup).defaultView;
82-
const accordionItemElements = window.document.querySelectorAll('div[data-accordion-item]');
83-
const itemBody = accordionItemElements[0].querySelector('*[data-accordion-item-body]');
84-
const accordion = new Accordion(window);
85-
t.ok(accordion.expand, 'is defined');
86-
accordion.expand(accordionItemElements[0]);
87-
accordion.expand(accordionItemElements[1]);
88-
t.ok(accordionItemElements[0].hasAttribute('data-accordion-open'), 'mark accordion item open');
89-
t.ok(accordionItemElements[1].hasAttribute('data-accordion-open'), 'mark bodyless accordion item open');
90-
t.notEqual(itemBody.style.display, 'none', 'hides accordion item body when present');
30+
t.ok(accordion.item(0).element);
9131
t.end();
9232
});

src/lib/accordion-item.js

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
export default class AccordionItem {
2+
constructor(element) {
3+
this.element = element;
4+
this.closed = this.element.hasAttribute('data-accordion-closed');
5+
this.open = this.element.hasAttribute('data-accordion-open');
6+
7+
if (this.closed) {
8+
this.collapse();
9+
}
10+
11+
if (this.open) {
12+
this.expand();
13+
}
14+
}
15+
16+
collapse() {
17+
const itemBody = this.element.querySelector('[data-accordion-item-body]');
18+
19+
if (!this.element.hasAttribute('data-accordion-closed')) {
20+
this.element.setAttribute('data-accordion-closed', true);
21+
22+
if (this.element.hasAttribute('data-accordion-open')) {
23+
this.element.removeAttribute('data-accordion-open');
24+
}
25+
26+
if (itemBody) {
27+
itemBody.style.display = 'none';
28+
}
29+
30+
this.open = false;
31+
this.closed = true;
32+
}
33+
}
34+
35+
expand() {
36+
const itemBody = this.element.querySelector('[data-accordion-item-body]');
37+
38+
if (!this.element.hasAttribute('data-accordion-open')) {
39+
this.element.setAttribute('data-accordion-open', true);
40+
41+
if (this.element.hasAttribute('data-accordion-closed')) {
42+
this.element.removeAttribute('data-accordion-closed');
43+
}
44+
45+
if (itemBody) {
46+
itemBody.style.display = '';
47+
}
48+
49+
this.open = true;
50+
this.closed = false;
51+
}
52+
}
53+
}

src/lib/accordion-item.spec.js

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import tap from 'tap';
2+
import {jsdom} from 'jsdom';
3+
import AccordionItem from './accordion-item';
4+
5+
tap.test('AccordionItem exists', (t) => {
6+
t.ok(AccordionItem);
7+
t.end();
8+
});
9+
10+
tap.test('#collapse method', (t) => {
11+
const markup = `
12+
<div data-accordion-item>
13+
<div data-accordion-item-body></div>
14+
</div>
15+
<div data-accordion-item data-accordion-open></div>
16+
`;
17+
const window = jsdom(markup).defaultView;
18+
const itemBody = window.document.querySelector('[data-accordion-item-body]');
19+
let items = window.document.querySelectorAll('[data-accordion-item]');
20+
21+
items = [].map.call(items, item => new AccordionItem(item));
22+
23+
t.ok(items[0].collapse, 'is defined');
24+
25+
t.ok(items[0].closed === false, 'accordion item is open');
26+
t.ok(items[1].closed === false, 'bodyless accordion item is open');
27+
t.equal(itemBody.style.display, "", 'item body is visible');
28+
29+
items[0].collapse();
30+
items[1].collapse();
31+
32+
t.ok(items[0].closed === true, 'accordion item is closed');
33+
t.ok(items[1].closed === true, 'bodyless accordion item is closed');
34+
t.equal(itemBody.style.display, 'none', 'item body is not visible');
35+
t.end();
36+
});
37+
38+
tap.test('#expand method', (t) => {
39+
const markup = `
40+
<div data-accordion-item>
41+
<div data-accordion-item-body style="display: none;"></div>
42+
</div>
43+
<div data-accordion-item data-accordion-closed></div>
44+
`;
45+
const window = jsdom(markup).defaultView;
46+
const itemBody = window.document.querySelector('[data-accordion-item-body]');
47+
let items = window.document.querySelectorAll('[data-accordion-item]');
48+
49+
items = [].map.call(items, item => new AccordionItem(item));
50+
51+
t.ok(items[0].expand, 'is defined');
52+
53+
t.ok(items[0].open === false, 'accordion item is closed');
54+
t.ok(items[1].open === false, 'bodyless accordion item is closed');
55+
t.equal(itemBody.style.display, 'none', 'item body is visible');
56+
57+
items[0].expand();
58+
items[1].expand();
59+
60+
t.ok(items[0].open === true, 'accordion item is open');
61+
t.ok(items[1].open === true, 'bodyless accordion item is open');
62+
t.equal(itemBody.style.display, '', 'item body is not visible');
63+
t.end();
64+
});

0 commit comments

Comments
 (0)