Skip to content

Instantly share code, notes, and snippets.

@tlimpanont
Last active July 5, 2016 13:33
Show Gist options
  • Save tlimpanont/3edfdd10f4701c398809 to your computer and use it in GitHub Desktop.
Save tlimpanont/3edfdd10f4701c398809 to your computer and use it in GitHub Desktop.
collapsible grid content blocks
.detail-col {
transition: max-height .2s linear;
}
.detail-col:not(:nth-child(-n+3)){
overflow: hidden;
visibility: hidden;
}
.detail-col.collapsed {
max-height: 0px;
visibility: hidden;
}
.collapsible-button .icon {
transition: transform 1s ease-out;
transform: rotateX(180deg);
}
.collapsible-button.collapsed .icon {
transform: rotateX(0deg);
}
/**
* Content block which can collaps and expand
* @param {Object} options
* @returns CollapsibleContentBlocks
*/
var CollapsibleContentBlocks = function(options) {
var self = this;
var elementsVisible = 3 || options.elementsVisible;
this.options = _.extend({
elementsVisible: elementsVisible,
afterNElementSelector: '.detail-col:not(:nth-child(-n+' + elementsVisible + '))',
collapsibleButtonSelector: '.collapsible-button',
collapsedClassName: 'collapsed'
}, options);
this.lastMaxHeight = DOM.outerHeight(this.getOuterHeighestNode());
this.collapsibleButton = document.querySelector(this.options.collapsibleButtonSelector);
this.collapsibleButton.addEventListener('click', this.collapsibleClickHandler.bind(this));
/**
* When resizing just caculate the height as a percentage
* but when stop resizing set the height back into a px value
* @param
* @returns
*/
var resizeTimer;
window.addEventListener('resize', function() {
if (!self.isCollapsed()) {
var lastMaxHeight = DOM.outerHeight(self.getOuterHeighestNode());
self.getOuterHeighestNode().style.maxHeight = (
DOM.outerHeight(self.getOuterHeighestNode()) / DOM.outerHeight(document.body)
) * 100 + '%';
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
self.getOuterHeighestNode().style.maxHeight = lastMaxHeight + 'px';
}, 10);
}
});
// set the button and the blocks as collapsed state
this.setCollapsed();
} || {};
CollapsibleContentBlocks.prototype.isCollapsed = function() {
var self = this;
return document.querySelector(self.options.afterNElementSelector)
.classList.contains(self.options.collapsedClassName);
};
CollapsibleContentBlocks.prototype.collapsibleClickHandler = function(event) {
var self = this;
DOM.toggleClass(self.collapsibleButton, self.options.collapsedClassName);
DOM.nodeListToArray(
document.querySelectorAll(self.options.afterNElementSelector)
).forEach(function(node) {
if (node.classList.contains('collapsed')) {
node.style.maxHeight = self.lastMaxHeight + 'px';
node.style.visibility = 'visible';
node.classList.remove(self.options.collapsedClassName);
} else {
self.lastMaxHeight = DOM.outerHeight(self.getOuterHeighestNode());
node.classList.add(self.options.collapsedClassName);
node.removeAttribute('style');
}
});
};
CollapsibleContentBlocks.prototype.setCollapsed = function() {
var self = this;
DOM.nodeListToArray(
document.querySelectorAll(self.options.afterNElementSelector)
).forEach(function(node) {
node.classList.add(self.options.collapsedClassName);
});
this.collapsibleButton.classList.add(this.options.collapsedClassName);
};
/**
* Get the node with the highest outerHeight
*/
CollapsibleContentBlocks.prototype.getOuterHeighestNode = function() {
var self = this;
return DOM.nodeListToArray(
document.querySelectorAll(self.options.afterNElementSelector)
).sort(function(nodeA, nodeB) {
return DOM.outerHeight(nodeB) - DOM.outerHeight(nodeA);
})[0];
};
var toggleClass = function(el, className) {
if (el.classList) {
el.classList.toggle(className);
} else {
var classes = el.className.split(' ');
var existingIndex = classes.indexOf(className);
if (existingIndex >= 0)
classes.splice(existingIndex, 1);
else
classes.push(className);
el.className = classes.join(' ');
}
};
var nodeListToArray = function(nl) {
for (var a = [], l = nl.length; l--; a[l] = nl[l]);
return a;
};
var outerHeight = function(el) {
var height = el.offsetHeight;
var style = getComputedStyle(el);
height += parseInt(style.marginTop) + parseInt(style.marginBottom);
return height;
};
var outerWidth = function(el) {
var width = el.offsetWidth;
var style = getComputedStyle(el);
width += parseInt(style.marginLeft) + parseInt(style.marginRight);
return width;
};
window.DOM = {
toggleClass: toggleClass,
nodeListToArray: nodeListToArray,
outerHeight: outerHeight,
outerWidth: outerWidth
}
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://code.jquery.com/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<!-- MODULE -->
<script type="text/javascript" src="DOM.js"></script>
<script type="text/javascript" src="tele2.collapsible.content.blocks.js"></script>
<link rel="stylesheet" type="text/css" href="tele2.collapsible.content.blocks.css">
<!-- END MODULE -->
<title>JS Bin</title>
<script type="text/javascript">
window.onload = function() {
new CollapsibleContentBlocks();
}
</script>
</head>
<body>
<div class="container content">
<div class="row">
<div class="col-xs-4 detail-col">
<h1>Title</h1>
<p>
<img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=350%C3%97150&w=350&h=150" alt="" class="img-responsive img-thumbnail">
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Expedita magni sint voluptatem, nobis aliquam, quas cum mollitia facere sit inventore modi aperiam. Aspernatur, facilis ex officia, eaque nam excepturi doloribus?
</p>
</div>
<div class="col-xs-4 detail-col">
<h1>This is title</h1>
<p>
<img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=350%C3%97150&w=350&h=150" alt="" class="img-responsive img-thumbnail">
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Expedita magni sint voluptatem, nobis aliquam, quas cum mollitia facere sit inventore modi aperiam. Aspernatur, facilis ex officia, eaque nam excepturi doloribus?
</p>
</div>
<div class="col-xs-4 detail-col">
<h1>This is title</h1>
<p>
<img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=350%C3%97150&w=350&h=150" alt="" class="img-responsive img-thumbnail">
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Expedita magni sint voluptatem, nobis aliquam, quas cum mollitia facere sit inventore modi aperiam. Aspernatur, facilis ex officia, eaque nam excepturi doloribus?
</p>
</div>
<div class="clearfix"></div>
<div class="col-xs-4 detail-col">
<h1>This is title</h1>
<p>
<img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=350%C3%97150&w=350&h=150" alt="" class="img-responsive img-thumbnail">
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Expedita magni sint voluptatem, nobis aliquam, quas cum mollitia facere sit inventore modi aperiam. Aspernatur, facilis ex officia, eaque nam excepturi doloribus?
</p>
<p>
<img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=350%C3%97150&w=350&h=150" class="img-thumbnail" />
</p>
</div>
<div class="col-xs-4 detail-col">
<h1>This is title</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Expedita magni sint voluptatem, nobis aliquam, quas cum mollitia facere sit inventore modi aperiam. Aspernatur, facilis ex officia, eaque nam excepturi doloribus?</p>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-xs-12 text-center">
<button class="btn collapsible-button"><i class="icon glyphicon glyphicon-menu-down"></i></button>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<h1>Title</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquid ut cupiditate cumque quibusdam aut quisquam, eaque officiis molestias. Doloremque iste natus sit temporibus quae aperiam ad quibusdam porro id numquam.
</p>
<h4>Title 2</h4>
<h5>
<small>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</small>
</h5>
</div>
</div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment