<html lang="en">
<head>
<meta name="description" content="Using bootstrap's slideshow to present multiple categories">
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="slideshows-placeholder">
<!-- slideshows will be inserted here -->
</div>
<div class="categorybuttons-placeholder">
<!-- category buttons will be inserted here -->
</div>
</div>
</body>
</html>
body{
background: #f3f3f3;
}
.carousel-inner > .item > img,
.carousel-inner > .item > a > img {
width: 70%;
margin: auto;
}
.slideshows-placeholder{
border: 4px solid tomato;
min-height: 120px;
}
.categorybuttons-placeholder{
margin-top: 8px;
}
a.x-button{
display:inline-block;
margin-right: 8px;
padding: 8px;
color:#333;
transition: width 2s; /* Safari */
transition: width 2s;
text-decoration:none;
}
.x-button:hover{
background:#fff;
}
.x-button.active{
background:tomato;
}
/*
possible future work...
- clean and optimize code
*/
/*images from http://themes.themolitor.com/wpbm/fixed-grid-layout/*/
var categories = [
{
'id': '#category_a',
'name': 'Category A',
'slides': [
{
img: 'http://themes.themolitor.com/wpbm/files/2011/05/tumblr_mqq4ivpL641st5lhmo1_1280-280x170.jpg',
title: 'Foo Category A',
desc: 'My lorem Foo'
},
{
img: 'http://img.estadao.com.br/resources/jpg/1/9/1433021762291.jpg',
title: 'Foo Category A',
desc: 'My lorem Foo'
},
{
img: 'http://themes.themolitor.com/wpbm/files/2011/05/tumblr_mpp6mqgvVh1st5lhmo1_1280-280x170.jpg'
},
{
img: 'http://themes.themolitor.com/wpbm/files/2011/05/tumblr_ms9n2dS1qE1st5lhmo1_12801-280x170.jpg',
title: 'Bar Category A',
desc: 'My lorem Bar desc'
}
],
},
{
'id': '#category_b',
'name': 'Category B',
'slides': [
{
img: 'http://themes.themolitor.com/wpbm/files/2011/05/tumblr_mrraevBLsP1st5lhmo1_12801-280x170.jpg',
title: 'Foo Category B',
desc: 'My lorem Foo'
},
{
img: 'http://themes.themolitor.com/wpbm/files/2011/05/16Gz2hU-280x170.jpg'
},
{
img: 'http://themes.themolitor.com/wpbm/files/2011/05/1eRBRVa-280x170.jpg',
title: 'Bar Category B',
desc: 'My lorem Bar desc'
}
]
}
]
var $sp = $('.slideshows-placeholder'),
$cbp = $('.categorybuttons-placeholder');
new SlideByCategory({
slideshowsPlaceholder: $sp, //the place where slideshows must be inserted
//each category has it's own slideshow
categorybuttonsPlaceholder: $cbp, // the buttons that reveal the slideshow
categories: categories,
onRenderFinish: function(){
$cbp.on('click','.x-button', function(e){
e.preventDefault();
var $el = $(this);
$el.siblings().removeClass('active');
$el.addClass('active');
var $carousels = $sp.find('.carousel');
$carousels.hide();
var $targetCarousel = $carousels.filter($el.attr('data-id'))
if ($targetCarousel.data('bs.slideshow')){
$targetCarousel.carousel();
$targetCarousel.show();
} else {
$targetCarousel.show();
}
})
$cbp.find('.x-button').first().click();
}
})
/*
The MIT License (MIT)
Copyright (c) 2015 marcio reis - marcio.reis@outlook.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/**
*
* @param {object} options The configuration object
* @param {string} options.id The slideshow category ID. ID must be prefixed with #
* @param {string} options.name The name that will be shown in the button
*
* @param {array} options.slides
* @param {string} options.slides[index].img The image url
* @param {string} options.slides[index].title The title that will be shown along with the image
* @param {string} options.slides[index].desc The description that will be shown below the title
* @param {function} options.onRenderFinish This function is executed when the slideshow structure is ready. It provides the slide show as argument
*/
function SlideByCategory(options){
var totalCategories = options.categories.length
this.render = function(){
$.each(options.categories,function(key, category){
var $button = $('<a href="" class="x-button" data-id="'+category.id+'">' + category.name +'</a>');
new DynamicCarousel({
id: category.id,
slides: category.slides,
activateFirst: true,
//returns the carousel DOM structure according to the plugin convention
onRenderFinish: function($el){
$el.appendTo(options.slideshowsPlaceholder);
}
})
$button.appendTo(options.categorybuttonsPlaceholder);
if ( key + 1 == totalCategories){
options.onRenderFinish();
}
})
}
this.render();
}
/*
The MIT License (MIT)
Copyright (c) 2015 marcio reis - marcio.reis@outlook.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/**
*
*
* @param {object} options The configuration object
* @param {string} options.id The slideshow ID. Must include the #
* @param {array} options.slides
* @param {string} options.slides[index].img The image url
* @param {string} options.slides[index].title The title that will be shown along with the image
* @param {string} options.slides[index].desc The description that will be shown below the title
* @param {function} options.onRenderFinish This function is executed when the slideshow structure is ready. It provides the slide show as argument
*/
function DynamicCarousel(options){
var slide="";
slide += "<div class=\"item\">";
slide += " <img src=\"\" alt=\"\" width=\"460\" height=\"345\">";
slide += " <div class=\"carousel-caption\">";
slide += " <h3 class='title'><\/h3>";
slide += " <p class='desc'><\/p>";
slide += " <\/div>";
slide += " <\/div>";
var $slide = $(slide);
var leftControlTmpl="";
leftControlTmpl += "<a class=\"left carousel-control\" href=\""+options.id+"\" role=\"button\" data-slide=\"prev\">";
leftControlTmpl += " <span class=\"glyphicon glyphicon-chevron-left\" aria-hidden=\"true\"><\/span>";
leftControlTmpl += " <span class=\"sr-only\">Previous<\/span>";
leftControlTmpl += " <\/a>";
var rightControlTmpl="";
rightControlTmpl += "<a class=\"right carousel-control\" href=\""+ options.id+"\" role=\"button\" data-slide=\"next\">";
rightControlTmpl += " <span class=\"glyphicon glyphicon-chevron-right\" aria-hidden=\"true\"><\/span>";
rightControlTmpl += " <span class=\"sr-only\">Next<\/span>";
rightControlTmpl += " <\/a>";
this.$carousel = $('<div />', {
id: options.id.replace('#',''),
class: 'carousel slide'
})
this.$carousel.attr('data-ride','carousel');
this.$indicators = $('<ol />', {
class: 'carousel-indicators'
})
this.$inner = $('<div />',{
class: 'carousel-inner'
})
this.$inner.attr('role','listbox');
this.$leftControl = $(leftControlTmpl)
this.$rightControl = $(rightControlTmpl)
this.totalSlides = options.slides.length;
this.slides = options.slides;
var _that = this;
this.build = function(){
$.each(this.slides, function(index, slide){
var $indicatorEl = _that.buildIndicator(index);
var $slideEl = _that.buildSlider(slide)
_that.$indicators.append($indicatorEl);
_that.$inner.append($slideEl);
if (options.activateFirst && index === 0){
$indicatorEl.addClass('active');
$slideEl.addClass('active');
}
if (index+1 === _that.totalSlides){
_that.$carousel.append(_that.$indicators);
_that.$carousel.append(_that.$inner);
_that.$carousel.append(rightControlTmpl);
_that.$carousel.append(leftControlTmpl);
options.onRenderFinish(_that.$carousel)
}
})
}
this.buildIndicator = function(index){
var indicator = "<li data-target=\""+options.id+"\" data-slide-to=\""+index+"\"></li>";
return $(indicator);
};
this.buildSlider = function(slide){
var $e = $slide.clone(),
$img = $e.find('img'),
$caption = $e.find('.carousel-caption'),
$title = $caption.find('h3'),
$desc = $caption.find('p');
$img.attr('src', slide.img);
if (!slide.desc && !slide.title){
$caption.remove();
} else {
if (slide.desc){
$desc.html(slide.desc);
}
if (slide.title){
$title.html(slide.title);
$img.attr('alt', slide.img);
}
}
return $e;
}
this.build();
}
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |