Skip to content

Commit

Permalink
Add accordion sample
Browse files Browse the repository at this point in the history
  • Loading branch information
cletusw committed Aug 9, 2012
1 parent 000a263 commit 34d00f4
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 0 deletions.
103 changes: 103 additions & 0 deletions samples/accordion/accordion-component.html
@@ -0,0 +1,103 @@
<!DOCTYPE html>
<html>
<head>
<title>Accordion Component</title>
<link rel="stylesheet" type="text/css" href="../../src/debug.css">
</head>
<body>
<element name="accordion" extends="div">
<template>
<content></content>
</template>
<script>
if (this !== window) {
this.lifecycle({
created: function(root) {
this.root = root;
var selectedSection = this.selectedSection = this.querySelector('section');
setTimeout(function() {

This comment has been minimized.

Copy link
@dglazkov

dglazkov Aug 9, 2012

Not sure why you need a timeout here.

This comment has been minimized.

Copy link
@cletusw

cletusw Aug 9, 2012

Author Owner

The problem is that the accordion is created before the accordion-section components (with their necessary 'selected' setters). I tried listening for the 'upgrade' event specified in the spec, but it was never getting fired. Just to test, I even put this code:

<script> var section = document.querySelector('section'); console.log(section); section.addEventListener('upgrade', function() { console.log(this); }); </script>

just before the tag, and it was still only logging the first section element once instead of twice. So this is just a hack. I'll add that in a comment.

This comment has been minimized.

Copy link
@dglazkov

dglazkov Aug 10, 2012

Then perhaps the selected item should fire an event and the accordion could listen to it?

This comment has been minimized.

Copy link
@cletusw

cletusw Aug 10, 2012

Author Owner

You mean the accordion-section element should fire its own upgrade event?

This comment has been minimized.

Copy link
@dglazkov

dglazkov Aug 10, 2012

No, not the upgrade event. Whenever a section element is selected, it should fire "selected" event. Then the accordion can listen to it and set the appropriate value. Does this make sense?

This comment has been minimized.

Copy link
@cletusw

cletusw Aug 10, 2012

Author Owner

Ah, okay. My bad. That would mean putting the listeners on each section individually instead of one overall on the accordion. That still wouldn't fix this problem, though, since I'm trying to select the first one before any have been clicked. I want the first one to start open.

This comment has been minimized.

Copy link
@dglazkov

dglazkov Aug 10, 2012

Ok, perhaps I need to explain the strategy a bit more:

  1. one listener for "selected" event on [is=accordion]
  2. the listener takes the target and sets this.selectedSection, unselecting the previous one.
  3. in [is=section], "create" callback, the section checks to see if it's firstChild of [is=accordion]
  4. if it is, it fires "selected" event.
  5. also, every time you click on the title, the [is=section] simply fires "selected" event.

As a result, you'll have the logic of selecting/unselecting things in the actual accordion (the controller). The section components only fire events.

Does this make sense?

This comment has been minimized.

Copy link
@cletusw

cletusw via email Aug 10, 2012

Author Owner

This comment has been minimized.

Copy link
@cletusw

cletusw Aug 13, 2012

Author Owner

What if we'd like to have the [is=accordion] start with an [is=section] other than the first shown? Then wouldn't it make sense to have the initial selecting happen in the controller (so it could receive an argument to its constructor to select a different one)?

This comment has been minimized.

Copy link
@cletusw

cletusw Aug 13, 2012

Author Owner

I've added a an attempt to allow default selections beyond the first child in commit 6099384. I believe it works quite well. Also, your strategy would be insanely simple to implement if the @host rule were working. Do you know its status? Then I could get rid of the 'selected' property of the accordion-sections and its getter/setter and simply use a CSS rule:

@host.selected div {
    display: block;
}

This comment has been minimized.

Copy link
@cletusw

cletusw Aug 14, 2012

Author Owner

Sorry, I meant:

@host {
    .selected {
        display: block;
    }
}

This comment has been minimized.

Copy link
@dglazkov

dglazkov Aug 15, 2012

Yup. @host is coming soon :)

Can't wait to merge this in. Do you need to make a new pull request?

This comment has been minimized.

Copy link
@cletusw

cletusw Aug 15, 2012

Author Owner

I haven't implemented the strategy you mentioned 5 days ago (above), but if the current implementation is satisfactory, then I think you could just merge in this pull request as is. Do you think I should refactor it to match that strategy you mentioned?

This comment has been minimized.

Copy link
@dglazkov

dglazkov Aug 15, 2012

I'll merge as is, but would love to see another patch to remove setTimeout. setTimeouts are nasty :)

This comment has been minimized.

Copy link
@cletusw

cletusw via email Aug 15, 2012

Author Owner
selectedSection.selected = true;
}, 10);

// Attach listeners
this.addEventListener('click', function(event) {
var clickedSection = event.target.parentElement;
if (clickedSection.selected === false) {
selectedSection.selected = false;
clickedSection.selected = true;
selectedSection = clickedSection;
}
});
}
});
}
</script>
</element>
<element name="accordion-section" extends="section">
<template>
<style scoped>

This comment has been minimized.

Copy link
@dglazkov

dglazkov Aug 9, 2012

Shouldn't need "scoped" anymore. Styles are now implicitly scoped within shadow DOM.

header {
cursor: pointer;
}
div {
display: none;
}
div.selected {
display: block;
}
</style>
<header>
<content select="h2:first-of-type"></content>
</header>
<div>
<content></content>
</div>
</template>
<script>
if (this !== window) {
this.lifecycle({
created: function(root) {
// Define instance properties
Object.defineProperties(this, {

This comment has been minimized.

Copy link
@dglazkov

dglazkov Aug 9, 2012

What's wrong with just this._root = root, etc.? :)

This comment has been minimized.

Copy link
@cletusw

cletusw Aug 9, 2012

Author Owner

Hmm, you're right. For some reason I was using 'not enumerable' to mean 'private' even though that's what the underscore is for.

_root: {
value: root
},
_content: {
value: root.querySelector('div')
},
_selected: {
value: false,
writable: true
}
});
}
});

this.generatedConstructor.prototype = Object.create(Object.prototype, {

This comment has been minimized.

Copy link
@dglazkov

dglazkov Aug 9, 2012

This can be just:

this.generatedConstructor.prototype = {

This comment has been minimized.

Copy link
@cletusw

cletusw Aug 9, 2012

Author Owner

Awesome. I didn't know that using that syntax still preserved the link to Object.prototype. Should have known. That's why we have Object.create(null, ...).

selected: {
get: function() {
return this._selected;
},
set: function(selected) {
if (this._selected !== selected) {
if (selected === true) {
this.classList.add('selected');
this._content.classList.add('selected');
}
else {
this.classList.remove('selected');
this._content.classList.remove('selected');
}

this._selected = selected;
}
},
enumerable: true,
configurable: true
}
});
}
</script>
</element>
</body>
</html>
112 changes: 112 additions & 0 deletions samples/accordion/index.html
@@ -0,0 +1,112 @@
<!DOCTYPE html>
<html>
<head>
<title>Accordion Component Example</title>
<link rel="components" href="accordion-component.html">
<script src="../../src/components-polyfill.js"></script>
<style>
/* These styles are based on the CSS accordion here:
* http://www.hongkiat.com/blog/css-content-accordion/
*/
html {
overflow-y: scroll;
}
body {
font-family: sans-serif;
font-size: 13px;
}
.accordion {
width: 830px;
overflow: hidden;
margin: 10px auto;
padding: 10px;
color: #474747;
background: #414141;
}
.accordion section {
overflow: hidden;
margin-bottom: 6px;
padding: 10px;
color: #333;
background: white;
}
.accordion section:last-of-type {
margin-bottom: 0;
}
.accordion h2 {
margin: -10px;
padding: 8px 10px;
font-size: 16px;
font-weight: normal;
color: #eee;
background: #333;
}
.accordion h2:hover {
background: #444;
}
.accordion .selected h2 {
color: inherit;
background: none;
}
.contact label {
display: block;
}
</style>
</head>
<body>
<h1>Accordion Component Example</h1>

<div is="accordion" class="accordion">
<section is="accordion-section">
<h2>About Us</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse id lobortis massa. Nunc viverra velit leo, sit amet elementum mi. Fusce posuere nunc a mi tempus malesuada. Curabitur facilisis rhoncus eros eget placerat. Aliquam semper mauris sit amet justo tempor nec lacinia magna molestie. Etiam placerat congue dolor vitae adipiscing. Aliquam ac erat lorem, ut iaculis justo. Etiam mattis dignissim gravida. Aliquam nec justo ante, non semper mi. Nulla consectetur interdum massa, vel porta enim vulputate sed. Maecenas elit quam, egestas eget placerat non, fringilla vel eros. Nam vehicula elementum nulla sed consequat. Phasellus eu erat enim. Praesent at magna non massa dapibus scelerisque in eu lorem.</p>
</section>

<section is="accordion-section">
<h2>Services</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse id lobortis massa. Nunc viverra velit leo, sit amet elementum mi. Fusce posuere nunc a mi tempus malesuada. Curabitur facilisis rhoncus eros eget placerat.</p>
<p>Aliquam semper mauris sit amet justo tempor nec lacinia magna molestie. Etiam placerat congue dolor vitae adipiscing. Aliquam ac erat lorem, ut iaculis justo. Etiam mattis dignissim gravida. Aliquam nec justo ante, non semper mi. Nulla consectetur interdum massa, vel porta enim vulputate sed.</p>
<p>Maecenas elit quam, egestas eget placerat non, fringilla vel eros. Nam vehicula elementum nulla sed consequat. Phasellus eu erat enim. Praesent at magna non massa dapibus scelerisque in eu lorem.</p>
</section>

<section is="accordion-section">
<h2>Blog</h2>
<article>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse id lobortis massa. Nunc viverra velit leo, sit amet elementum mi. Fusce posuere nunc a mi tempus malesuada. Curabitur facilisis rhoncus eros eget placerat.</p>
</article>
<article>
<p>Aliquam semper mauris sit amet justo tempor nec lacinia magna molestie. Etiam placerat congue dolor vitae adipiscing. Aliquam ac erat lorem, ut iaculis justo. Etiam mattis dignissim gravida. Aliquam nec justo ante, non semper mi. Nulla consectetur interdum massa, vel porta enim vulputate sed.</p>
</article>
<article>
<p>Maecenas elit quam, egestas eget placerat non, fringilla vel eros. Nam vehicula elementum nulla sed consequat. Phasellus eu erat enim. Praesent at magna non massa dapibus scelerisque in eu lorem.</p>
</article>
</section>

<section is="accordion-section">
<h2>Portfolio</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<ul>
<li>Suspendisse id lobortis massa. Nunc viverra velit leo, sit amet elementum mi</li>
<li>Fusce posuere nunc a mi tempus malesuada. Curabitur facilisis rhoncus eros eget placerat</li>
<li>Aliquam semper mauris sit amet justo tempor nec lacinia magna molestie. Etiam placerat congue dolor vitae adipiscing</li>
<li>Aliquam ac erat lorem, ut iaculis justo. Etiam mattis dignissim gravida</li>
<li>Aliquam nec justo ante, non semper mi. Nulla consectetur interdum massa, vel porta enim vulputate sed</li>
<li>Maecenas elit quam, egestas eget placerat non, fringilla vel eros. Nam vehicula elementum nulla sed consequat</li>
<li>Phasellus eu erat enim. Praesent at magna non massa dapibus scelerisque in eu lorem.</li>
</ul>
</section>

<section is="accordion-section">
<h2>Contact</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse id lobortis massa.</p>
<form class="contact">
<label>Lorem<input type="text" /></label>
<label>Ipsum<input type="password" /></label>
<label>Dolor<input type="radio" /></label>
<label>Sit<input type="checkbox" /></label>
<input type="submit" />
</form>
</section>
</div>
</body>
</html>

4 comments on commit 34d00f4

@dglazkov
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having sections as separate components is an interesting approach. It let the actual accordion be just a simple controller. I agree, it would be cool to have only is="accordion", and the rest of it "just work", but I think this sample is worth preserving in its present form.

@cletusw
Copy link
Owner Author

@cletusw cletusw commented on 34d00f4 Aug 9, 2012

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for learning purposes, do you know how I could do that? Can I 'upgrade' the section components from within the create method of the accordion component? Or is there some way to use loops/repeated templates in the parent component and not even make the children components at all?

@dglazkov
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One way to do this would be to use the same approach as the Tab Manager example and simply distribute contents of the accordion component into the right insertion points. This would mean that you can't use

to group the accordion title and contents.

@cletusw
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. Thanks!

Please sign in to comment.