Skip to content

Instantly share code, notes, and snippets.

@jonurry
Created March 26, 2018 17:25
Show Gist options
  • Save jonurry/f04be3c611e620844d2c66b2fa6f2870 to your computer and use it in GitHub Desktop.
Save jonurry/f04be3c611e620844d2c66b2fa6f2870 to your computer and use it in GitHub Desktop.
15.3 Looping a triangle (Eloquent JavaScript Solutions)
<style>
button {
background-color: whitesmoke;
}
.selected {
background-color: white;
}
</style>
<tab-panel>
<div data-tabname="one">Tab one</div>
<div data-tabname="two">Tab two</div>
<div data-tabname="three">Tab three</div>
</tab-panel>
<script>
function clickTab(e) {
let tabs = e.target.parentNode.parentNode.querySelectorAll('[data-tabname]');
for (let tab of tabs) {
if (tab.getAttribute('data-tabname') == e.target.textContent) {
tab.hidden = false;
} else {
tab.hidden = true;
};
};
e.target.parentNode.childNodes.forEach((node) => {
node.className = '';
});
e.target.className = 'selected';
};
function asTabs(node) {
let buttons = document.createElement('div');
let first = true;
for (let tab of node.children) {
let button = document.createElement('button');
button.textContent = tab.getAttribute('data-tabname');
button.onclick = clickTab;
if (first) {
button.className = 'selected';
tab.hidden = false;
first = false;
} else {
tab.hidden = true;
}
buttons.appendChild(button);
}
node.insertBefore(buttons, node.firstChild);
}
asTabs(document.querySelector("tab-panel"));
</script>
@jonurry
Copy link
Author

jonurry commented Mar 26, 2018

15.3 Tabs

Tabbed panels are widely used in user interfaces. They allow you to select an interface panel by choosing from a number of tabs “sticking out” above an element.

In this exercise, you must implement a simple tabbed interface. Write a function, asTabs, that takes a DOM node and creates a tabbed interface showing the child elements of that node. It should insert a list of <button> elements at the top of the node, one for each child element, containing text retrieved from the data-tabname attribute of the child. All but one of the original children should be hidden (given a display style of none). The currently visible node can be selected by clicking the buttons.

When that works, extend it to style the button for the currently selected tab differently, so that it is obvious which tab is selected.

@jonurry
Copy link
Author

jonurry commented Mar 26, 2018

Hints

One pitfall you might run into is that you can’t directly use the node’s childNodes property as a collection of tab nodes. For one thing, when you add the buttons, they will also become child nodes and end up in this object because it is a live data structure. For another, the text nodes created for the whitespace between the nodes are also in childNodes, but should not get their own tabs. You can use children instead of childNodes to ignore text nodes.

You could start by building up an array of tabs, so that you have easy access to them. To implement the styling of the buttons, you could store objects that contain both tab panel and its button.

I recommend writing a separate function for changing tabs. You can either store the previously selected tab, and only change the styles needed to hide that and show the new one, or you can just update the style of all tabs every time a new tab is selected.

You might want to call this function immediately, to make the interface start with the first tab visible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment