Модальные окна Bootstrap

Однажды, на некоем сайте мне до жути понадобилось вызвать модальное окно. Bootstrap на страницах уже был, но, к сожалению, вся тема оформления ресурса представляла собой изуродованный оригинальный код этой библиотеки и её стилей. Поэтому вызвать окно, прицепив шикарную библиотеку Bootstrap3-dialog не удалось. Разбираться в ней и пытаться заставить её работать хоть как-то не хотелось.

Короче, проще было переписать её заново. Получилось, по-моему, гораздо компактнее и не так уж и плохо.

(function() {
  /**
   * Bootstrap Window simple function.
   * 
   * @author Lex http://numidium.ru/
   * 
   * @params {Object} params Window parameters.
   *
   * @returns nothing.
   * 
   * Parameters are:
   *   title {String}               - Window title,
   *   message {String}             - Window message,
   *   onload(methods) {Function}   - Function fired after window loaded, see methods below.
   *   onunload(methods) {Function} - Function, that fires when window unloaded.
   *   dismissable {Bool}           - Dismissable by user flag.
   *   size {String}                - Window width; 'normal' (default), 'small' or 'large'.
   *   buttons {Object}             - See below.
   * 
   * Methods in callbacks:
   *   At this moment only one: dismiss();
   *
   * Buttons object:
   *   Should be either {'button label': function(methods) {}},
   *   or {'button label': {'class': 'className', click: function(methods) {}}}
   *
   * Class names for buttons: Regular Bootstrap class names for buttons:
   *   'btn-default',
   *   'btn-primary',
   *   'btn-success',
   *   'btn-warning',
   *   'btn-danger',
   *   'btn-info',
   *   'btn-link',
   *   'btn-lg',
   *   'btn-sm',
   *   'btn-xs',
   *   'btn-block',
   *   'active',
   *   'disabled'.
   * Classes can be combined with space separator (this is regular HTML attribute).
   */
  var bsWindow = function(params) {
    // Settings defaults
    params = params || {};

    var settings = {
      title: 'Default title',
      message: 'Default content',
      buttons: {},
      onload: function() {},
      onunload: function() {},
      dismissable: true,
      size: 'normal'
    };

    $.extend(settings, params);

    // Generate unique modal id:
    var modalId = 'modal'+Date.now();
    modalId += Math.floor(Math.random()*1000);

    // Generating template:
    var template = [
      '<div class="modal fade" id="'+modalId+'" role="dialog">',
        '<div class="modal-dialog'+(settings.size=='small'?' modal-sm':''), (settings.size == 'large'?' modal-lg': '')+'">',
        '<div class="modal-content">',
          '<div class="modal-header">',
            settings.dismissable ? '<button type="button" class="close" data-dismiss="modal">&times;</button>':'',
            '<h4 class="modal-title">'+settings.title+'</h4>',
          '</div>',
          '<div class="modal-body">',
            settings.message,
          '</div>',
        '</div>',
      '</div>',
    '</div>'
    ].join('');

    $(document.body).append(template);

    // Creating callback methods list:
    var methods = {
      dismiss: function() {
        $('#'+modalId).modal('hide');
      }
    };

    // onload event fired:
    settings.onload(methods);

    /**
     * Create button function:
     * @param {String} title        Button title.
     * @param {Object} actionParams Action params object or function (see above).
     * @param {Number} iter         Iterator for unique button ids.
     *
     * @return nothing.
     */
    var createButton = function(title, actionParams, iter) {
      // Generate footer, if not exist:
      if ($('#' + modalId + ' .modal-footer').length === 0) {
        $('#'+modalId + ' .modal-content').append('<div class="modal-footer"></div>');
      }

      // Unique id for button:
      var newId = 'btn'+Date.now();
      newId += iter;

      $('#'+modalId + ' .modal-footer').append('<button id="'+newId+'" class="btn '+actionParams.class+'">'+title+'</button>');

      $('#'+newId).click(function() { actionParams.click(methods); });
    };

    // Appending buttons if there is some:
    var i=0; // Iterator is needed, because Google Chrome
             // is too fast to create multiple buttons in
             // the same microsecond!

    for(var k in settings.buttons) {
      // Default parameters for buttons:
      var btnParams = {
        'click': function(){},
        'class': 'btn-default'
      };

      if (typeof settings.buttons[k] === 'function') {
        btnParams.click = settings.buttons[k];
      } else {
        $.extend(btnParams, settings.buttons[k]);
      }

      createButton(k, btnParams, i);
      i++;
    }

    // If the window dismissable, disable keyboard dismiss ability and click outside window ability:
    var modalOpts = {};
    if (!settings.dismissable) modalOpts = {
      backdrop: 'static',  
      keyboard: 'false'  
    };

    // Show the modal:
    $('#'+modalId).modal(modalOpts);

    // Finally, fire unload event and remove the modal completely:
    $('#'+modalId).on('hidden.bs.modal', function() {
      settings.onunload(methods);
      $('#'+modalId).remove();
    });
  }; //bsWindow();

  bsWindow({
    title: 'Large modal window',
    message: 'A large modal window content; not dismissable',
    buttons: {
      'Нефиг': {
        class: 'btn-primary',
        click: function(methods) {
          bsWindow({
            title: 'Small modal window',
            message: 'A small-size modal window...',
            size: 'small'
          });
          methods.dismiss();
        }
      },
      'Нафиг': {
        'click': function(methods) { methods.dismiss(); },
        'class': 'btn-warning'
      },
      'Пофиг': function(methods) {
        bsWindow({
          title: 'Normal modal window',
          message: 'A normal modal window...'
        });
        methods.dismiss();
      },
      'Test (does nothing)': {
        class: 'btn-success disabled'
      }
    },
    onload: function() { /*console.log('loaded');*/ },
    onunload: function() { /*console.log('unloaded');*/ },
    dismissable: false,
    size: 'large'
  });

})();
Modified: 2016-12-11 00:00:00