Now that we have our plugin well declared, we must fill the logic for it. We will create methods inside the prototype to create this behavior. We will only show this portion of the plugin code here.
The first method that we will create is init(). We will call it later to start the plugin. Before that, we have a few steps:
Actually, we have only one requirement from the Bootstrap original carousel plugin: the outmost div must have an id. Let's create the init function while making this assertion:
BootstrapCarousel.prototype = {
init: function () {
if(!this.$element.attr('id')){
throw 'You must provide an id for the Bootstrap Carousel element.';
}
this.$element.addClass('slide carousel');
}
};Therefore, we check if the element has the attribute id using this.$element.attr('id'). If not, we throw an error to the console and the developer will properly fix this issue. Note that we can access the plugin element using this.$element because we made this assignment at the start of the plugin.
In the last line of the function, we added some classes needed for the Bootstrap Carousel, in case we do not have it in the $element such as .slide and .carousel.
To load the Bootstrap Carousel template, let's create another function called load inside the init method to start it:
BootstrapCarousel.prototype = {
init: function () {
if(!this.$element.attr('id')){
throw 'You must provide an id for the Bootstrap Carousel element.';
}
this.$slides = this.$element.find('> img');
this.$element.addClass('slide carousel');
this.load();
}
load: function() {
},
};First, we must remove any Carousel elements that could be already present inside our $element. The elements that we must remove are the ones with the .carousel-inner, .carousel-indicators, and .carousel-control classes. Also, we have to load and hide the slide images in the variable this.$slides:
load: function() {
// removing Carousel elements
this.$element.find('.carousel-inner, .carousel-indicators, .carousel-control').remove();
// loading and hiding the slide images
this.$slides = this.$element.find('> img');
this.$slides.hide();
},Next, we must make sure that there are not any other associations of Bootstrap Carousel in our plugin element. Append the following lines in the function:
this.$element.carousel('pause');
this.$element.removeData('bs.carousel');First, we will pause the Carousel to stop any interaction and after use the function removeData in the bs.carousel, which is the name of the Carousel plugin.
To continue, we must load the Bootstrap Carousel template. Inside the class prototype, we have to create a variable to hold the original template. The variable will have the following format:
template: {
slide: '…',
carouselInner: '…',
carouselItem: '…',
carouselIndicator: '…',
carouselIndicatorItem: '…',
carouselControls: '…',
},We are not going to place the full code of each template because it is quite extensive, and it would be better to you to check the full code attached with the book and see each template. Although there are no secrets in the templates, they are just a big string with some marked parts that we will replace. The marked parts are defined as a string around curly brackets, for example, {keyName}. When creating the template, we just need to replace these parts of the string by calling .replace(/{keyName}/, 'value').
Each key inside the template correspond to a certain part of the template. Let's explain each one:
slide: This is the slide template of the new plugin and it is used to add slides via JavaScriptcarouselInner: This is the element inside the carousel that is parent for the itemscarouselItem: This is the item that contains the image and the caption of a slidecarouselIndicator: This is the set of bullets at the bottom of the carouselcarouselIndicatorItem: This represents each bullet of the indicatorcarouselControls: This is the controls to switch between left and right the carousel slidesAt the end of the load method, add two more lines:
load: function() {
this.$element.find('.carousel-inner, .carousel-indicators, .carousel-control').remove();
this.$slides = this.$element.find('> img');
this.$slides.hide();
this.$element.carousel('pause');
this.$element.removeData('bs.carousel');
this.$element.append(this.createCarousel());
this.initPlugin();
},So, we will append in the this.$element the template generated in the function createCarousel. After that, we just need to initialize the Bootstrap original Carousel plugin.
The original template will be created in the function createCarousel. It is composed of two steps. The steps are as follows:
.carousel-inner elementThus, the createCarousel method is composed of the call of these three functions that will append the string template to a variable:
createCarousel: function() {
var template = '';
// create slides
template += this.createSlideDeck();
// create indicators
if(this.options.indicators) {
template += this.createIndicators();
}
// create controls
if(this.options.controls) {
template += this.createControls();
}
return template
},Note that for the indicator and the controls we made, check before creating the template. We performed a check in the this.options variable to see if the developer passed the argument to add these components or not.
So, we are defining the first two variables of our plugin. They can be passed through data attributes in the element, like data-indicators and data-controls. It defines whether the template will have these elements or not.
The slide deck will be created by the iterating of each this.$slide and loading the image source, the data-title and the data-content in this case. Also, for the first item, we must apply the class .active. The code is as follows:
createSlideDeck: function() {
var slideTemplate = '',
slide;
for (var i = 0; i < this.$slides.length; i++) {
slide = this.$slides.get(i);
slideTemplate += this.createSlide(
i == 0 ? 'active' : '',
slide.src,
slide.dataset.title,
slide.dataset.content
);
};
return this.template.carouselInner.replace(/{innerContent}/, slideTemplate);
},In each iteration, we are calling another function named createSlide, where we are passing, if the slide is active, the image source, the item title, and the item content. This function will then replace the template using these arguments:
createSlide: function(active, itemImg, itemTitle, itemContent) {
return this.template.carouselItem
.replace(/{activeClass}/, active)
.replace(/{itemImg}/, itemImg)
.replace(/{itemTitle}/, itemTitle || this.options.defaultTitle)
.replace(/{itemContent}/, itemContent || this.options.defaultContent);
}We performed a check for the title and the content. If there is no title or content provided, a default value will be assigned from this.options. Just like the indicators and controls, these options can be passed through data attributes such as data-default-title and data-default-content in the plugin HTML element.
The function
createIndicators is used to create the indicators. In this function, we will perform the same method of the one to create the slide deck. We will create each bullet and then wrap it in the list of .carousel-indicators:
createIndicators: function() {
var indicatorTemplate = '',
slide,
elementId = this.$element.attr('id');
for (var i = 0; i < this.$slides.length; i++) {
slide = this.$slides.get(i);
indicatorTemplate += this.template.carouselIndicatorItem
.replace(/{elementId}/, elementId)
.replace(/{slideNumber}/, i)
.replace(/{activeClass}/, i == 0 ? 'class="active"' : '');
}
return this.template.carouselIndicator.replace(/{indicators}/, indicatorTemplate);
},The only trick here is that each bullet must be enumerated and have a reference to the parent element id. Thus, we made the replacements for each this.$slides and returned the indicator template.
The controls create the arrows to switch slides from left to right. They follow the same methodology as the other templates. Just get a template and replace the keys. This method must be implemented like this:
createControls: function() {
var elementId = this.$element.attr('id');
return this.template.carouselControls
.replace(/{elementId}/g, elementId)
.replace(/{previousIcon}/, this.options.previousIcon)
.replace(/{previousText}/, this.options.previousText)
.replace(/{nextIcon}/, this.options.nextIcon)
.replace(/{nextText}/, this.options.nextText);
},Note that in the first replacement for the {elementId}, our regex has an append g. The g on the regex is used to replace all occurrences of the following pattern. If we do not use g, JavaScript will only replace the first attempt. In this template we have two {elementId} keys, using which we replace both at once.
We also have some options passed through plugin initialization for the previous and next icon and the text corresponding to that.
After creating the original template, we must start the original Carousel plugin. We defined a function called initPlugin with the following implementation:
initPlugin: function() {
this.$element.carousel({
interval: this.options.interval,
pause: this.options.pause,
wrap: this.options.wrap,
keyboyard: this.options.keyboard
});
},It just starts the plugin by calling this.$element.carousel while passing the carousel options on start. The options are loaded just like the others that we presented before. As shown, the options are loaded in the plugin class definition in the following line:
this.options = $.extend({}, BootstrapCarousel.DEFAULTS, options);If any option is passed, it will override the default options present in BootstrapCarousel.DEFAULTS. We must create like this:
BootstrapCarousel.DEFAULTS = {
indicators: true,
controls: true,
defaultTitle: '',
defaultContent: '',
nextIcon: 'glyphicon glyphicon-chevron-right',
nextText: 'Next',
previousIcon: 'glyphicon glyphicon-chevron-left',
previousText: 'Previous',
interval: 5000,
pause: 'hover',
wrap: true,
keyboard: true,
};We are one step away from loading the plugin. To do so, create the following code in the HTML:
<div id="carousel-notification" class="bootstrap-carousel" data-indicators="true" data-controls="true"> <img src="imgs/doge.jpg" data-title="doge" data-content="Hey there!"> <img src="imgs/laika.jpg" data-title="laika" data-content="Hey ...!"> <img src="imgs/cat.jpg" data-title="cat"> </div>
In our plugin JavaScript, we have to ignite the prototype by calling the init function like this:
var BootstrapCarousel = function (element, options) {
this.$element = $(element);
this.options = $.extend({}, BootstrapCarousel.DEFAULTS, options);
this.init();
}Hooray! Open the HTML file in our browser and see the plugin in action, as shown in the next screenshot. In the DOM, you can how we perfectly mime the Bootstrap Carousel plugin, reducing the declaration in almost 35 lines of code:
