-
Notifications
You must be signed in to change notification settings - Fork 195
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Collapse): added bs-collapse component for collapsible content
- Loading branch information
1 parent
0fe2b43
commit 794b52d
Showing
8 changed files
with
331 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ bower_components/ | |
tests/ | ||
tmp/ | ||
dist/ | ||
docs/ | ||
|
||
.bowerrc | ||
.editorconfig | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
import Ember from 'ember'; | ||
|
||
export default Ember.Component.extend({ | ||
|
||
classNameBindings: ['collapse','in','collapsing'], | ||
attributeBindings: ['style'], | ||
|
||
/** | ||
* Collapsed/expanded state | ||
* | ||
* @property collapsed | ||
* @type boolean | ||
* @default true | ||
* @public | ||
*/ | ||
collapsed: true, | ||
|
||
/** | ||
* True if this item is expanded | ||
* | ||
* @property active | ||
* @protected | ||
*/ | ||
active: false, | ||
|
||
collapse: Ember.computed.not('transitioning'), | ||
collapsing: Ember.computed.alias('transitioning'), | ||
in: Ember.computed.and('collapse', 'active'), | ||
|
||
/** | ||
* true if the component is currently transitioning | ||
* | ||
* @property transitioning | ||
* @type boolean | ||
* @protected | ||
*/ | ||
transitioning: false, | ||
|
||
/** | ||
* @property collapseSize | ||
* @type number | ||
* @protected | ||
*/ | ||
collapseSize: null, | ||
|
||
/** | ||
* The size of the element when collapsed. Defaults to 0. | ||
* | ||
* @property collapsedSize | ||
* @type number | ||
* @default 0 | ||
* @public | ||
*/ | ||
collapsedSize: 0, | ||
|
||
/** | ||
* The size of the element when expanded. When null the value is calculated automatically to fit the containing elements. | ||
* | ||
* @property expandedSize | ||
* @type number | ||
* @default null | ||
* @public | ||
*/ | ||
expandedSize: null, | ||
|
||
/** | ||
* Usually the size (height) of the element is only set while transitioning, and reseted afterwards. Set to true to always set a size. | ||
* | ||
* @property resetSizeWhenNotCollapsing | ||
* @type boolean | ||
* @default true | ||
* @private | ||
*/ | ||
resetSizeWhenNotCollapsing: true, | ||
|
||
|
||
/** | ||
* The direction (height/width) of the collapse animation. | ||
* When setting this to 'width' you should also define custom CSS transitions for the width property, as the Bootstrap | ||
* CSS does only support collapsible elements for the height direction. | ||
* | ||
* @property collapseDimension | ||
* @type string | ||
* @default 'height' | ||
* @public | ||
*/ | ||
collapseDimension: 'height', | ||
|
||
style: Ember.computed('collapseSize', function () { | ||
var size = this.get('collapseSize'), | ||
dimension = this.get('collapseDimension'); | ||
if (Ember.isEmpty(size)) { | ||
return new Ember.Handlebars.SafeString(''); | ||
} | ||
return new Ember.Handlebars.SafeString(`${dimension}: ${size}px`); | ||
}), | ||
|
||
|
||
/** | ||
* Triggers the show transition | ||
* | ||
* @method show | ||
* @protected | ||
*/ | ||
show: function () { | ||
var complete = function () { | ||
this.set('transitioning', false); | ||
if (this.get('resetSizeWhenNotCollapsing')) { | ||
this.set('collapseSize', null); | ||
} | ||
this.sendAction('didShow'); | ||
}; | ||
|
||
this.sendAction('willShow'); | ||
|
||
this.setProperties({ | ||
transitioning: true, | ||
collapseSize: this.get('collapsedSize'), | ||
active: true | ||
}); | ||
|
||
if (!Ember.$.support.transition) { | ||
return complete.call(this); | ||
} | ||
|
||
this.$() | ||
.one('bsTransitionEnd', Ember.run.bind(this, complete)) | ||
// @todo: make duration configurable | ||
.emulateTransitionEnd(350) | ||
; | ||
|
||
Ember.run.next(this, function () { | ||
if (!this.get('isDestroyed')) { | ||
this.set('collapseSize', this.getExpandedSize('show')); | ||
} | ||
}); | ||
}, | ||
|
||
/** | ||
* Get the size of the element when expanded | ||
* | ||
* @method getExpandedSize | ||
* @param $action | ||
* @returns number | ||
* @private | ||
*/ | ||
getExpandedSize: function($action) { | ||
var expandedSize = this.get('expandedSize'); | ||
if (Ember.isPresent(expandedSize)) { | ||
return expandedSize; | ||
} | ||
|
||
var collapseElement = this.$(), | ||
prefix = $action === 'show' ? 'scroll' : 'offset', | ||
measureProperty = Ember.String.camelize(prefix + '-' + this.get('collapseDimension')); | ||
return collapseElement[0][measureProperty]; | ||
}, | ||
|
||
/** | ||
* Triggers the hide transition | ||
* | ||
* @method hide | ||
* @protected | ||
*/ | ||
hide: function () { | ||
|
||
var complete = function () { | ||
this.set('transitioning', false); | ||
if (this.get('resetSizeWhenNotCollapsing')) { | ||
this.set('collapseSize', null); | ||
} | ||
this.sendAction('didHide'); | ||
}; | ||
|
||
this.sendAction('willHide'); | ||
|
||
this.setProperties({ | ||
transitioning: true, | ||
collapseSize: this.getExpandedSize('hide'), | ||
active: false | ||
}); | ||
|
||
if (!Ember.$.support.transition) { | ||
return complete.call(this); | ||
} | ||
|
||
this.$() | ||
.one('bsTransitionEnd', Ember.run.bind(this, complete)) | ||
// @todo: make duration configurable | ||
.emulateTransitionEnd(350) | ||
; | ||
|
||
Ember.run.next(this, function () { | ||
if (!this.get('isDestroyed')) { | ||
this.set('collapseSize', this.get('collapsedSize')); | ||
} | ||
}); | ||
}, | ||
|
||
_onCollapsedChange: Ember.observer('collapsed', function () { | ||
var collapsed = this.get('collapsed'), | ||
active = this.get('active'); | ||
if (collapsed !== active) { | ||
return; | ||
} | ||
if (collapsed === false) { | ||
this.show(); | ||
} | ||
else { | ||
this.hide(); | ||
} | ||
}), | ||
|
||
didInsertElement: function() { | ||
this.set('active', !this.get('collapsed')); | ||
}, | ||
|
||
_updateCollapsedSize: Ember.observer('collapsedSize', function() { | ||
if (!this.get('resetSizeWhenNotCollapsing') && this.get('collapsed') && !this.get('collapsing')) { | ||
this.set('collapseSize', this.get('collapsedSize')); | ||
} | ||
}), | ||
|
||
_updateExpandedSize: Ember.observer('expandedSize', function() { | ||
if (!this.get('resetSizeWhenNotCollapsing') && !this.get('collapsed') && !this.get('collapsing')) { | ||
this.set('collapseSize', this.get('expandedSize')); | ||
} | ||
}) | ||
|
||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import Ember from 'ember'; | ||
import component from 'ember-bootstrap/components/bs-collapse'; | ||
|
||
export default component; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import Ember from 'ember'; | ||
|
||
export default Ember.Controller.extend({ | ||
collapsed: true, | ||
notCollapsed: Ember.computed.not('collapsed'), | ||
|
||
actions: { | ||
toggle() { | ||
this.toggleProperty('collapsed'); | ||
} | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<h1>Collapse</h1> | ||
|
||
{{#bs-button toggle=true active=notCollapsed action="toggle"}}{{#if collapsed}}Show{{else}}Hide{{/if}}{{/bs-button}} | ||
|
||
<hr/> | ||
|
||
{{#bs-collapse collapsed=collapsed}} | ||
<div class="well"> | ||
<h2>Collapse</h2> | ||
<p>This is collapsible content</p> | ||
</div> | ||
{{/bs-collapse}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { | ||
moduleForComponent, | ||
test | ||
} from 'ember-qunit'; | ||
import hbs from 'htmlbars-inline-precompile'; | ||
|
||
|
||
moduleForComponent('bs-collapse', 'Integration | Component | bs-collapse', { | ||
integration: true | ||
}); | ||
|
||
|
||
test('collapse has correct default markup', function(assert) { | ||
this.render(hbs`{{#bs-collapse}}<p>Just some content</p>{{/bs-collapse}}`); | ||
assert.equal(this.$(':first-child').hasClass('collapse'), true, 'collapse has collapse class'); | ||
assert.equal(this.$(':first-child').hasClass('in'), false, 'collapse does not have in class'); | ||
|
||
}); | ||
|
||
test('expanded collapse has correct default markup', function(assert) { | ||
this.render(hbs`{{#bs-collapse collapsed=false}}<p>Just some content</p>{{/bs-collapse}}`); | ||
assert.equal(this.$(':first-child').hasClass('collapse'), true, 'collapse has collapse class'); | ||
assert.equal(this.$(':first-child').hasClass('in'), true, 'collapse has in class'); | ||
}); | ||
|
||
|
||
|
||
test('setting collapse to false expands this item', function(assert) { | ||
this.set('collapsed', true); | ||
this.render(hbs`{{#bs-collapse collapsed=collapsed}}<p>Just some content</p>{{/bs-collapse}}`); | ||
this.set('collapsed', false); | ||
|
||
assert.equal(this.$(':first-child').hasClass('collapsing'), true, 'collapse has collapsing class while transition is running'); | ||
|
||
|
||
var done = assert.async(); | ||
|
||
// wait for transitions to complete | ||
setTimeout(() => { | ||
assert.equal(this.$(':first-child').hasClass('collapse'), true, 'collapse has collapse class'); | ||
assert.equal(this.$(':first-child').hasClass('in'), true, 'collapse has in class'); | ||
|
||
done(); | ||
}, 500); | ||
|
||
|
||
}); | ||
|
||
test('setting collapse to true collapses this item', function(assert) { | ||
this.set('collapsed', false); | ||
this.render(hbs`{{#bs-collapse collapsed=collapsed}}<p>Just some content</p>{{/bs-collapse}}`); | ||
this.set('collapsed', true); | ||
|
||
assert.equal(this.$(':first-child').hasClass('collapsing'), true, 'collapse has collapsing class while transition is running'); | ||
|
||
var done = assert.async(); | ||
|
||
// wait for transitions to complete | ||
setTimeout(() => { | ||
assert.equal(this.$(':first-child').hasClass('collapse'), true, 'collapse has collapse class'); | ||
assert.equal(this.$(':first-child').hasClass('in'), false, 'collapse does not have in class'); | ||
|
||
done(); | ||
}, 500); | ||
|
||
|
||
}); | ||
|
||
|