Adapting Bootstrap JavaScript Plugins - Extending Bootstrap (2014)

Extending Bootstrap (2014)

Chapter 6. Adapting Bootstrap JavaScript Plugins

In this chapter, you will learn how to make the most out of the jQuery plugins that come bundled with Bootstrap. You will first learn why you should go through the trouble of customizing plugins, then understand how to do the actual customization, and finally find out how to extend the plugins properly.

Why customize plugins?

There are basically two different ways to customize the Bootstrap plugins. You can either apply your own style to alter their appearance or you can extend the functionality of the plugins to make them do what you want.

Normally, it is enough to simply apply your own style to the plugins, but occasionally, you will need to extend the functionality of the plugins to produce the desired result. The following are a few advantages to consider when customizing plugins:

· Saves time: Customizing the existing plugins can save you an immense amount of time compared to writing your own jQuery plugins. When you use the Bootstrap plugins, you get decent base styles for the plugins that can easily be modified and you do not need to write the styles from scratch.

· Fairly well written: Most of the plugins that come with Bootstrap are fairly well written and can easily be extended to do more. Back when Bootstrap was new, it was quite hard to customize the plugins, and some of them even came with a few bugs. However, things have changed since then and the plugins in the latest Bootstrap 3 are production-ready.

· Divided opinions: Some developers say that the Bootstrap plugins are bad and should not be used for anything other than prototyping. These developers are missing out because even if they are not the best jQuery plugins, they are still quite decent and are viable options that should be considered.

Customizing plugins

Now that you know why you should customize plugins, it is time to add some customized plugins to your Bootstrap project as shown in the following steps:

1. First open index.html and add the following code snippet directly after the <nav> element at the top of the page:

2. <div id="carousel" class="carousel slide" data-ride="carousel">

3. <ol class="carousel-indicators">

4. <li data-target="#carousel" data-slide-to="0" class="active"></li>

5. <li data-target="#carousel" data-slide-to="1"></li>

6. <li data-target="#carousel" data-slide-to="2"></li>

7. </ol>

8. <div class="carousel-inner">

9. <div class="item active">

10. <div class="carousel-caption">Slide 1</div>

11. </div>

12. <div class="item">

13. <div class="carousel-caption">Slide 2</div>

14. </div>

15. <div class="item">

16. <div class="carousel-caption">Slide 3</div>

17. </div>

18. </div>

19. <a class="left carousel-control" href="#carousel" data-slide="prev"><span class="glyphicon glyphicon-chevron-left"></span></a>

20. <a class="right carousel-control" href="#carousel" data-slide="next"><span class="glyphicon glyphicon-chevron-right"></span></a>

</div>

21. Next, open custom-theme.less and add the following code snippet:

22..carousel {

23. // create a new shade of @brand-primary.

24. background: lighten(@brand-primary, 35%);

25. max-height: 560px;

26. margin: -20px 0 40px;

27. width: 100%;

28.}

29..carousel-indicators {

30. bottom: -23px;

31. text-align: right;

32.

33. li {

34. // set width and height equal to 15px.

35. .square(15px);

36. background: #fff;

37. border-color: @brand-primary;

38.

39. // "&" refers to the parent element (li).

40. &:hover {

41. border-color: lighten(@brand-primary, 10%);

42. }

43.

44. &.active {

45. .square(17px);

46. background-color: @brand-primary;

47. }

48. }

49.}

50..carousel-inner > .item {

51. max-height: 560px;

52. overflow: hidden;

53.

54. > img {

55. margin-top: -100px;

56. width: 100%;

57. }

58.}

59..carousel-caption {

60. background-color: @brand-primary;

61. font-size: 1.5em;

62. padding: 10px;

63. text-align: left;

64. text-shadow: none;

65.}

66..carousel-control {

67. color: @brand-primary;

68. font-size: 3em;

69. opacity: 1;

70. text-shadow: none;

71.

72. &:hover {

73. color: lighten(@brand-primary, 10%);

74. }

75.

76. &.left, &.right {

77. background: none;

78. }

}

79. Now, if you recompile your styles, you should see the result as shown in the following screenshot. Customizing the plugins is just like customizing any Bootstrap components; find out which styles you need to override and do so.

Customizing plugins

Next, we will take a look at how we can make the plugins do more.

Extending Bootstrap plugins

Sometimes, you need to extend the functionality of the Bootstrap plugins, and when you do, it is important that you know how to do it correctly. There are many ways to extend plugins. We will cover a single approach that you can implement in your projects to extend any Bootstrap plugin.

As an example, let us take a look at how you can extend the Bootstrap Modal plugin.

Create a new JavaScript file named custom-modal.js and add the following contents:

(function ($) {

// enable ES5 strict mode

'use strict';

// save the original plugin

var _parent = $.fn.modal;

// define your own constructor

var Modal = function(element, options) {

_parent.Constructor.apply(this, arguments);

// console.log calls are here just to see that our method is called.

console.log('modal initialized');

};

// set custom default options

Modal.DEFAULTS = $.extend({}, _parent.Constructor.DEFAULTS, {

backdrop: 'static'

});

// extend the prototype for your plugin from the original plugin

Modal.prototype = Object.create(_parent.Constructor.prototype);

// define a method for easy access to parent methods

Modal.prototype.parent = function() {

var args = $.makeArray(arguments),

method = args.shift();

_parent.Constructor.prototype[method].apply(this, args)

};

// override the show method to demonstrate

Modal.prototype.show = function() {

this.parent('show');

console.log('show called');

};

// override the actual jQuery plugin method

$.fn.modal = function (option, _relatedTarget) {

console.log('modal plugin called');

return this.each(function () {

var $this = $(this),

data = $this.data('bs.modal'),

options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option === 'object' && option);

if (!data) {

$this.data('bs.modal', (data = new Modal(this, options)));

}

if (typeof option === 'string') {

data[option](_relatedTarget);

} else if (options.show) {

data.show(_relatedTarget);

}

});

};

// override the plugin constructor

$.fn.modal.Constructor = Modal;

// override the plugin no-conflict method

$.fn.modal.noConflict = function() {

$.fn.modal = _parent;

return this;

};

})(jQuery);

Alright, that was quite a lot of code. Let us take a closer look at what the preceding code actually does:

1. To avoid polluting the global scope, everything is wrapped in an anonymous function that is invoked immediately with jQuery as its only argument. This is, nowadays, a common practice when working with JavaScript libraries:

2. (function ($) {

3. .....

})(jQuery);

4. First, we save the original plugin in a variable in the following way so that we can call its methods later on:

var _parent = $.fn.modal;

5. Then we define our own constructor, which is not absolutely necessary but is useful if we want to run custom code when the plugin is instantiated. It is defined as follows:

6. var Modal = function(element, options) {

7. _parent.Constructor.apply(this, arguments);

8. console.log('modal initialized');

};

9. Next, we define plugin options and their prototype by extending the default options and the prototype from the original plugin. We do it using the following code:

10.Modal.DEFAULTS = $.extend({}, _parent.Constructor.DEFAULTS, {

11. backdrop: 'static'

12.});

13.

Modal.prototype = Object.create(_parent.Constructor.prototype);

Note

If you want to learn more about prototypal inheritance in JavaScript, you can read about it on the Mozilla Developer Network website at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain.

14. Next, we define a parent method to allow us to call the methods from the original plugin easily and use that method to override the show method. This is done as follows:

15.Modal.prototype.parent = function() {

16. var args = $.makeArray(arguments),

17. method = args.shift();

18. _parent.Constructor.prototype[method].apply(this, args)

19.};

20.

21.Modal.prototype.show = function() {

22. this.parent('show');

23. console.log('show called');

};

24. Finally, we override the actual plugin method, its constructor, and the noConflict method with our own, as shown in the following code snippet:

25.$.fn.modal = function (option, _relatedTarget) {

26. console.log('modal plugin called');

27. return this.each(function () {

28. var $this = $(this),

29. data = $this.data('bs.modal'),

30. options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option === 'object' && option);

31.

32. if (!data) {

33. $this.data('bs.modal', (data = new Modal(this, options)));

34. }

35. if (typeof option === 'string') {

36. data[option](_relatedTarget);

37. } else if (options.show) {

38. data.show(_relatedTarget);

39. }

40. });

41.};

42.

43.$.fn.modal.Constructor = Modal;

44.

45.$.fn.modal.noConflict = function() {

46. $.fn.modal = _parent;

47. return this;

};

Now, you must be wondering why we need to override the jQuery plugin and its public methods. This is because, otherwise, our custom modal plugin would only exist within our anonymous function and would never be exposed to jQuery. It's a pity that we need to redefine the plugin and its methods, but there is really no way around this.

This might seem like an awful lot of code for such a small modification, but if you really want to extend the functionality of a plugin, this is the way to go. With this approach, there is almost no limit on what you can do. Most third party libraries that extend Bootstrap work in a similar manner. You could simplify the code a bit here and there, but that would make it less extendable and therefore also harder to work with.

The key benefits of using the previously mentioned approach for extending Bootstrap plugins are as follows:

· Extendable: This approach is focused on extendibility. The parent method allows you to call the original methods easily. You can also override every single method in the plugin to add some extra functionality with no trouble at all.

· Clean: There is no need to modify the code of the actual Bootstrap plugins. Instead, you create a new plugin by extending the original one and replacing the plugin with your own. All you need to do is load your code after you load the Bootstrap JavaScript.

· Based on best practices: This approach is written using the best JavaScript practices. Working with JavaScript can sometimes be tricky as every task can be done in so many ways and there is never a single correct solution.

Summary

You have now learned how to customize Bootstrap plugins by adding your own styles and by defining your own jQuery plugin that extends the original plugin.

In this chapter, you included a carousel plugin in your Bootstrap project and added some custom styles to it. You also learned how to extend the functionality of the Bootstrap plugins without modifying the original plugin.

In the next chapter, you will learn how the grid in Bootstrap works and how to customize it properly. You will customize the grid in your Bootstrap project and learn more about the responsiveness.