Deferred Bootstrap Modal

A wrapper to the standard Bootstrap Modal component that returns a promise that will be rejected or resolved via interaction with the modal.

HTML

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div class="modal fade" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title">Modal title</h4>
      </div>
      <div class="modal-body">
        <p>One fine body&hellip;</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary" data-promise-dispatch="resolve">Save changes</button>
      </div>
    </div><!-- /.modal-content -->
  </div><!-- /.modal-dialog -->
</div><!-- /.modal -->

JavaScript

/* jslint */

/**
 * @file bootstrap-modal-deferred.js provides a wrapper to the standard
 *       Bootstrap Modal component that returns a promise that will be rejected
 *       or resolved via interaction with the modal.
 * @version 1.0.0
 * @copyright Jim Auldridge <[email protected]> 2016
 * @license MIT
 * @see {@link https://github.com/JAAulde/bootstrap-modal-deferred|GitHub Repository}
 * @see {@link http://getbootstrap.com/javascript/#modals|Bootstrap Modal}
 * @see {@link https://api.jquery.com/category/deferred-object/|jQuery deferred}
 */
(function (context, undef) {
    'use strict';

    var $ = context.jQuery,
        defaults = {
            /*
             * By default, any dismissal of the modal (interaction with a
             * `data-dismiss="modal"` element) will reject the deferred
             */
            rejectOnDismiss: true,
            /*
             * If the plugin is called against a single element, then by default
             * the plugin will return the deferred instead of the collection.
             */
            returnDeferred: true
        },
        names = {
            DATA_ATTR_PROMISE_DISPATCH: 'data-promise-dispatch',
            DATA_KEY_PROMISE_DISPATCH: 'promiseDispatch',
            DATA_KEY_DEFERRED: 'modalDeferred',
            DATA_KEY_RETURN_DEFERRED: 'returnDeferred',
            DATA_KEY_REJECT_ON_DISMISS: 'rejectOnDismiss',
            VALUE_PENDING_DEFERRED_STATE: 'pending'
        },
        assignDeferred = function (dialog) {
            var deferred = $.Deferred();

            /*
             * The modal exists to allow for interactions that will resolve or
             * reject the deferred. Internal modification to the deferred's
             * state will handle closing it. External modifications should
             * result in the same as the interaction will no longer be needed.
             */
            deferred.always(function () {
                dialog.modal('hide');
            });

    ...