Skip to content

Commit

Permalink
Merge pull request #34 from truenorth/materialize-tabs
Browse files Browse the repository at this point in the history
Tabs
  • Loading branch information
Stefan Gasser committed Apr 10, 2015
2 parents 7b52e03 + 74468f2 commit a93f073
Show file tree
Hide file tree
Showing 15 changed files with 423 additions and 5 deletions.
36 changes: 36 additions & 0 deletions addon/components/materialize-tabs-tab.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Ember from 'ember';
import layout from '../templates/components/materialize-tabs-tab';

export default Ember.Component.extend({
layout: layout,
tagName: 'li',
classNames: ['materialize-tabs-tab', 'tab', 'col'],
classNameBindings: ['_colClass'],

colWidth: Ember.computed.alias('_tabSet.colWidth'),

_colClass: Ember.computed('colWidth', function () {
return 's' + this.get('colWidth');
}),

_tabSet: Ember.computed(function () {
return this.nearestWithProperty('___materializeTabs');
}),

_active: Ember.computed('_tabSet.selected', 'value', function () {
return this.get('_tabSet.selected') === this.get('value');
}),

click: function () {
this.trigger('tabClicked', this);
},

didInsertElement: function () {
this._super(...arguments);
var tabSet = this.get('_tabSet');
if (!tabSet) {
throw new Error('materialize-tabs-tab cannot be used outside the context of a materialize-tabs');
}
tabSet.registerTab(this);
}
});
71 changes: 71 additions & 0 deletions addon/components/materialize-tabs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import Ember from 'ember';
import layout from '../templates/components/materialize-tabs';
var map = Ember.EnumerableUtils.map;

export default Ember.Component.extend({
layout: layout,
content: null,
classNames: ['materialize-tabs', 'row'],
___materializeTabs: true,
_tabComponents: null,
numTabs: Ember.computed.alias('_tabComponents.length'),
selected: null,
optionValuePath: 'id',
optionLabelPath: 'title',
colWidth: 2,

init: function () {
this._super(...arguments);
this.set('_tabComponents', new Ember.A([]));
},

_updateIndicatorPosition: function (animate=true) {
var tabComponent = this.get('_tabComponents').filterBy('value', this.get('selected'))[0];
var tabSetRect = this.element.getBoundingClientRect();
if (tabComponent) {
var tabRect = tabComponent.element.getBoundingClientRect();

var cssParams = {
left: tabRect.left - tabSetRect.left,
right: tabSetRect.right - tabRect.right
};

if (!animate) {
this.$('.indicator').css(cssParams);
}
else {
this.$('.indicator1').velocity(cssParams, {duration: 150});
this.$('.indicator2').velocity(cssParams, {duration: 150, delay: 40});
}
}
},

_content: Ember.computed('content.[]', 'optionLabelPath', 'optionValuePath', function () {
var lp = this.get('optionLabelPath');
var vp = this.get('optionValuePath');
return new Ember.A(map(this.get('content') || [], c => ({id: c[vp], title: c[lp]})));
}),

didInsertElement: function () {
this._super(...arguments);
var tabComponents = this.get('_tabComponents');
if (this.get('selected') === null && tabComponents.length > 0) {
this.set('selected', tabComponents[tabComponents.length - 1].get('value'));
}
this._updateIndicatorPosition(false);
this.addObserver('selected', function () {
this._updateIndicatorPosition();
});
},

_setActiveTab: function (tabComponent) {
this.set('selected', tabComponent.get('value'));
},

registerTab: function (tabComponent) {
this.get('_tabComponents').addObject(tabComponent);
tabComponent.on('tabClicked', function (tab) {
this._setActiveTab(tab);
}.bind(this));
}
});
3 changes: 3 additions & 0 deletions addon/templates/components/materialize-tabs-tab.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<a {{bind-attr class="_active:active"}}>
{{title}}
</a>
10 changes: 10 additions & 0 deletions addon/templates/components/materialize-tabs.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<div class="col s12">
<ul class="tabs">
{{#each tab in _content}}
{{materialize-tabs-tab title=tab.title value=tab.id}}
{{/each}}
{{yield}}
<div class="indicator indicator1"></div>
<div class="indicator indicator2"></div>
</ul>
</div>
3 changes: 3 additions & 0 deletions app/components/materialize-tabs-tab.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import materializeTabsTab from 'ember-cli-materialize/components/materialize-tabs-tab';

export default materializeTabsTab;
3 changes: 3 additions & 0 deletions app/components/materialize-tabs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import materializeTabs from 'ember-cli-materialize/components/materialize-tabs';

export default materializeTabs;
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@
"ember-cli-qunit": "0.3.9",
"ember-cli-sass": "4.0.0-beta.4",
"ember-cli-uglify": "1.0.1",
"ember-export-application-global": "^1.0.2",
"ember-disable-prototype-extensions": "^1.0.0",
"ember-try": "0.0.3"
"ember-export-application-global": "^1.0.2",
"ember-try": "0.0.3",
"liquid-fire": "git+ssh://[email protected]:ef4/liquid-fire.git#8fcefd057478ab6852d7b8b3fc8526aa5079553c"
},
"description": "An ember-cli addon for using Materialize (CSS Framework based on Material Design) in Ember applications.",
"keywords": [
Expand Down
21 changes: 21 additions & 0 deletions tests/dummy/app/controllers/tabs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Ember from 'ember';

export default Ember.Controller.extend({
basicTabsContent: new Ember.A([
{id: 'a', title: 'First'},
{id: 'b', title: 'Second'},
{id: 'c', title: 'Third'}
]),
alternateTabsContent: new Ember.A([
{key: 'a', label: 'First'},
{key: 'b', label: 'Second'},
{key: 'c', label: 'Third'}
]),
basicTabsSelection: 'a',
secondTabsSelection: 'g',
actions: {
addTab: function () {
this.get('basicTabsContent').addObject({id: 'd', title: 'Fourth'});
}
}
});
5 changes: 3 additions & 2 deletions tests/dummy/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ var Router = Ember.Router.extend({
Router.map(function() {
this.route("badges");
this.route("buttons");
this.route("navbar");
this.route("copyright");
this.route("cards");
this.route("collapsible");
this.route("copyright");
this.route("input");
this.route("loader");
this.route("navbar");
this.route("parallax");
this.route("tabs");
});

export default Router;
4 changes: 4 additions & 0 deletions tests/dummy/app/templates/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@
{{#link-to 'parallax' class="collection-item"}}
Parallax{{#materialize-badge class="new"}}1{{/materialize-badge}}
{{/link-to}}

{{#link-to 'tabs' class="collection-item"}}
Tabs{{#materialize-badge class="new"}}1{{/materialize-badge}}
{{/link-to}}
</ul>
</div>

Expand Down
89 changes: 89 additions & 0 deletions tests/dummy/app/templates/tabs.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<div class="section index-banner">
<div class="container">
<div class="row">
<div class="col s12 m9">
<h1 class="header">Tabs</h1>
</div>
</div>
</div>
</div>

<div class='container'>
<div class="section">
<div class="intro">
<h4 class="col s12 header">The component supports several options:</h4>
<ul>
<li>content, default value <span class="default-value badge">[]</span> - tabs array</li>
<li>selected, default value <span class="default-value badge">null</span> - selected tab id</li>
<li>colWidth, default value <span class="default-value badge">2</span> - width of tabs, in grid columns</li>
</ul>
</div>
</div>

<div class="section">
<h4 class="col s12 header">Basic Usage</h4>
<p>Creating a basic set of tabs is simple, and you have several syntax options to choose from.
First, you can pass an array of tabs to the <code>&#123;&#123;materialize-tabs&#125;&#125;</code> component:</p>
<div class="tabs-example basic-tabs-example z-depth-1">
{{materialize-tabs
content=basicTabsContent
selected=basicTabsSelection}}
</div>

<pre class=" language-markup">
<code class=" col s8 language-markup">
<span>&#123;&#123;</span>materialize-tabs
content=tabSet
selected=selectedTabId<span>&#125;&#125;</span>
</code>
</pre>
<p>By default, the structure of the array of tabs is expected to look like this</p>

<pre class=" language-markup">
<code class=" col s8 language-markup">
[ {id: 'a', title: 'First'},
{id: 'b', title: 'Second'},
{id: 'c', title: 'Third'} ]
</code>
</pre>
<p>If you wish to use different key and value properties, you may specify some additional options</p>
<div class="tabs-example second-tabs-example z-depth-1">

{{materialize-tabs
content=alternateTabsContent
selected=basicTabsSelection
optionValuePath='key'
optionLabelPath='label'}}
</div>
<pre class=" language-markup">
<code class=" col s8 language-markup">
<span>&#123;&#123;</span>materialize-tabs
content=tabSet
selected=selectedTabId
optionValuePath='key'
optionLabelPath='label'<span>&#125;&#125;</span>
</code>
</pre>
<h4 class="col s12 header">Alternate Syntax</h4>
<p>The following syntax allows for more granular control over the particulars of each tab</p>
<div class="tabs-example third-tabs-example z-depth-1">
{{#materialize-tabs
selected=basicTabsSelection}}
{{materialize-tabs-tab value='a' title="Sixth"}}
{{materialize-tabs-tab value='b' title="Seventh"}}
{{materialize-tabs-tab value='c' title="Eighth"}}
{{/materialize-tabs}}
</div>
<pre class=" language-markup">
<code class=" col s8 language-markup">
<span>&#123;&#123;</span>#materialize-tabs selected=selectedTabId<span>&#125;&#125;</span>
<span>&#123;&#123;</span>materialize-tabs-tab value='a' title='Sixth'<span>&#125;&#125;</span>
<span>&#123;&#123;</span>materialize-tabs-tab value='b' title='Seventh'<span>&#125;&#125;</span>
<span>&#123;&#123;</span>materialize-tabs-tab value='c' title='Eighth'<span>&#125;&#125;</span>
<span>&#123;&#123;</span>/materialize-tabs<span>&#125;&#125;</span>
</code>
</pre>
</div>


</div>
2 changes: 1 addition & 1 deletion tests/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
{{content-for 'test-head'}}

<link rel="stylesheet" href="assets/vendor.css">
<link rel="stylesheet" href="assets/dummy.css">
<!-- <link rel="stylesheet" href="assets/dummy.css"> -->
<link rel="stylesheet" href="assets/test-support.css">

{{content-for 'head-footer'}}
Expand Down
30 changes: 30 additions & 0 deletions tests/integration/tabs-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Ember from 'ember';

import startApp from '../../tests/helpers/start-app';
import { test } from 'ember-qunit';

var App;

module('Tabs - Integration', {
setup: function() {
App = startApp();
},
teardown: function() {
Ember.run(App, 'destroy');
}
});


test('Basic Example - One set of tabs should be rendered, with three tabs', function(assert) {
visit('/tabs').then(function() {
assert.equal(find('.basic-tabs-example .materialize-tabs').length, 1, 'One set of tabs');
assert.equal(find('.basic-tabs-example .materialize-tabs .materialize-tabs-tab a').length, 3, 'Three tabs in the set');
assert.equal(find('.basic-tabs-example .materialize-tabs .materialize-tabs-tab:first-child a').text().trim(), 'First', 'Label of first tab is "First"');
assert.equal(find('.basic-tabs-example .materialize-tabs .materialize-tabs-tab:nth-child(2) a').text().trim(), 'Second', 'Label of second tab is "Second"');
assert.equal(find('.basic-tabs-example .materialize-tabs .materialize-tabs-tab:nth-child(3) a').text().trim(), 'Third', 'Label of third tab is "Third"');

assert.equal(find('.basic-tabs-example .materialize-tabs .materialize-tabs-tab:first-child .active').length, 1, 'First tab is initially selected');


});
});
4 changes: 4 additions & 0 deletions tests/unit/components/materialize-tabs-tab-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* Testing of this component is included in the materialize-tabs test cases, since this component
* cannot exist independently
*/
Loading

0 comments on commit a93f073

Please sign in to comment.