Custom Bootstrap modal

Demo on how to extend a Bootstrap plugin.

by David_Knowles

HTML

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.3/js/bootstrap.js"></script>
<!-- Button trigger modal -->
<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
  Launch demo modal
</button>

<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
        <h4 class="modal-title" id="myModalLabel">Modal title</h4>
      </div>
      <div class="modal-body">
        ...
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div><!-- /.modal-content -->
  </div><!-- /.modal-dialog -->
</div><!-- /.modal -->

JavaScript

// Custom Bootstrap modal 
(function ($) {
  '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('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 = $.extend({}, _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);

// test that the no-conflict method actually works
//$.fn.customModal = $.fn.modal.noConflict();
console.log('$.fn.modal: %s, $.fn.customModal: %s', $.fn.modal, $.fn.customModal);