986 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			986 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * bootbox.js [v4.4.0]
 | |
|  *
 | |
|  * http://bootboxjs.com/license.txt
 | |
|  */
 | |
| 
 | |
| // @see https://github.com/makeusabrew/bootbox/issues/180
 | |
| // @see https://github.com/makeusabrew/bootbox/issues/186
 | |
| (function (root, factory) {
 | |
| 
 | |
|   "use strict";
 | |
|   if (typeof define === "function" && define.amd) {
 | |
|     // AMD. Register as an anonymous module.
 | |
|     define(["jquery"], factory);
 | |
|   } else if (typeof exports === "object") {
 | |
|     // Node. Does not work with strict CommonJS, but
 | |
|     // only CommonJS-like environments that support module.exports,
 | |
|     // like Node.
 | |
|     module.exports = factory(require("jquery"));
 | |
|   } else {
 | |
|     // Browser globals (root is window)
 | |
|     root.bootbox = factory(root.jQuery);
 | |
|   }
 | |
| 
 | |
| }(this, function init($, undefined) {
 | |
| 
 | |
|   "use strict";
 | |
| 
 | |
|   // the base DOM structure needed to create a modal
 | |
|   var templates = {
 | |
|     dialog:
 | |
|       "<div class='bootbox modal' tabindex='-1' role='dialog'>" +
 | |
|         "<div class='modal-dialog'>" +
 | |
|           "<div class='modal-content'>" +
 | |
|             "<div class='modal-body'><div class='bootbox-body'></div></div>" +
 | |
|           "</div>" +
 | |
|         "</div>" +
 | |
|       "</div>",
 | |
|     header:
 | |
|       "<div class='modal-header'>" +
 | |
|         "<h4 class='modal-title'></h4>" +
 | |
|       "</div>",
 | |
|     footer:
 | |
|       "<div class='modal-footer'></div>",
 | |
|     closeButton:
 | |
|       "<button type='button' class='bootbox-close-button close' data-dismiss='modal' aria-hidden='true'>×</button>",
 | |
|     form:
 | |
|       "<form class='bootbox-form'></form>",
 | |
|     inputs: {
 | |
|       text:
 | |
|         "<input class='bootbox-input bootbox-input-text form-control' autocomplete=off type=text />",
 | |
|       textarea:
 | |
|         "<textarea class='bootbox-input bootbox-input-textarea form-control'></textarea>",
 | |
|       email:
 | |
|         "<input class='bootbox-input bootbox-input-email form-control' autocomplete='off' type='email' />",
 | |
|       select:
 | |
|         "<select class='bootbox-input bootbox-input-select form-control'></select>",
 | |
|       checkbox:
 | |
|         "<div class='checkbox'><label><input class='bootbox-input bootbox-input-checkbox' type='checkbox' /></label></div>",
 | |
|       date:
 | |
|         "<input class='bootbox-input bootbox-input-date form-control' autocomplete=off type='date' />",
 | |
|       time:
 | |
|         "<input class='bootbox-input bootbox-input-time form-control' autocomplete=off type='time' />",
 | |
|       number:
 | |
|         "<input class='bootbox-input bootbox-input-number form-control' autocomplete=off type='number' />",
 | |
|       password:
 | |
|         "<input class='bootbox-input bootbox-input-password form-control' autocomplete='off' type='password' />"
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   var defaults = {
 | |
|     // default language
 | |
|     locale: "en",
 | |
|     // show backdrop or not. Default to static so user has to interact with dialog
 | |
|     backdrop: "static",
 | |
|     // animate the modal in/out
 | |
|     animate: true,
 | |
|     // additional class string applied to the top level dialog
 | |
|     className: null,
 | |
|     // whether or not to include a close button
 | |
|     closeButton: true,
 | |
|     // show the dialog immediately by default
 | |
|     show: true,
 | |
|     // dialog container
 | |
|     container: "body"
 | |
|   };
 | |
| 
 | |
|   // our public object; augmented after our private API
 | |
|   var exports = {};
 | |
| 
 | |
|   /**
 | |
|    * @private
 | |
|    */
 | |
|   function _t(key) {
 | |
|     var locale = locales[defaults.locale];
 | |
|     return locale ? locale[key] : locales.en[key];
 | |
|   }
 | |
| 
 | |
|   function processCallback(e, dialog, callback) {
 | |
|     e.stopPropagation();
 | |
|     e.preventDefault();
 | |
| 
 | |
|     // by default we assume a callback will get rid of the dialog,
 | |
|     // although it is given the opportunity to override this
 | |
| 
 | |
|     // so, if the callback can be invoked and it *explicitly returns false*
 | |
|     // then we'll set a flag to keep the dialog active...
 | |
|     var preserveDialog = $.isFunction(callback) && callback.call(dialog, e) === false;
 | |
| 
 | |
|     // ... otherwise we'll bin it
 | |
|     if (!preserveDialog) {
 | |
|       dialog.modal("hide");
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   function getKeyLength(obj) {
 | |
|     // @TODO defer to Object.keys(x).length if available?
 | |
|     var k, t = 0;
 | |
|     for (k in obj) {
 | |
|       t ++;
 | |
|     }
 | |
|     return t;
 | |
|   }
 | |
| 
 | |
|   function each(collection, iterator) {
 | |
|     var index = 0;
 | |
|     $.each(collection, function(key, value) {
 | |
|       iterator(key, value, index++);
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   function sanitize(options) {
 | |
|     var buttons;
 | |
|     var total;
 | |
| 
 | |
|     if (typeof options !== "object") {
 | |
|       throw new Error("Please supply an object of options");
 | |
|     }
 | |
| 
 | |
|     if (!options.message) {
 | |
|       throw new Error("Please specify a message");
 | |
|     }
 | |
| 
 | |
|     // make sure any supplied options take precedence over defaults
 | |
|     options = $.extend({}, defaults, options);
 | |
| 
 | |
|     if (!options.buttons) {
 | |
|       options.buttons = {};
 | |
|     }
 | |
| 
 | |
|     buttons = options.buttons;
 | |
| 
 | |
|     total = getKeyLength(buttons);
 | |
| 
 | |
|     each(buttons, function(key, button, index) {
 | |
| 
 | |
|       if ($.isFunction(button)) {
 | |
|         // short form, assume value is our callback. Since button
 | |
|         // isn't an object it isn't a reference either so re-assign it
 | |
|         button = buttons[key] = {
 | |
|           callback: button
 | |
|         };
 | |
|       }
 | |
| 
 | |
|       // before any further checks make sure by now button is the correct type
 | |
|       if ($.type(button) !== "object") {
 | |
|         throw new Error("button with key " + key + " must be an object");
 | |
|       }
 | |
| 
 | |
|       if (!button.label) {
 | |
|         // the lack of an explicit label means we'll assume the key is good enough
 | |
|         button.label = key;
 | |
|       }
 | |
| 
 | |
|       if (!button.className) {
 | |
|         if (total <= 2 && index === total-1) {
 | |
|           // always add a primary to the main option in a two-button dialog
 | |
|           button.className = "btn-primary";
 | |
|         } else {
 | |
|           button.className = "btn-default";
 | |
|         }
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     return options;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * map a flexible set of arguments into a single returned object
 | |
|    * if args.length is already one just return it, otherwise
 | |
|    * use the properties argument to map the unnamed args to
 | |
|    * object properties
 | |
|    * so in the latter case:
 | |
|    * mapArguments(["foo", $.noop], ["message", "callback"])
 | |
|    * -> { message: "foo", callback: $.noop }
 | |
|    */
 | |
|   function mapArguments(args, properties) {
 | |
|     var argn = args.length;
 | |
|     var options = {};
 | |
| 
 | |
|     if (argn < 1 || argn > 2) {
 | |
|       throw new Error("Invalid argument length");
 | |
|     }
 | |
| 
 | |
|     if (argn === 2 || typeof args[0] === "string") {
 | |
|       options[properties[0]] = args[0];
 | |
|       options[properties[1]] = args[1];
 | |
|     } else {
 | |
|       options = args[0];
 | |
|     }
 | |
| 
 | |
|     return options;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * merge a set of default dialog options with user supplied arguments
 | |
|    */
 | |
|   function mergeArguments(defaults, args, properties) {
 | |
|     return $.extend(
 | |
|       // deep merge
 | |
|       true,
 | |
|       // ensure the target is an empty, unreferenced object
 | |
|       {},
 | |
|       // the base options object for this type of dialog (often just buttons)
 | |
|       defaults,
 | |
|       // args could be an object or array; if it's an array properties will
 | |
|       // map it to a proper options object
 | |
|       mapArguments(
 | |
|         args,
 | |
|         properties
 | |
|       )
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * this entry-level method makes heavy use of composition to take a simple
 | |
|    * range of inputs and return valid options suitable for passing to bootbox.dialog
 | |
|    */
 | |
|   function mergeDialogOptions(className, labels, properties, args) {
 | |
|     //  build up a base set of dialog properties
 | |
|     var baseOptions = {
 | |
|       className: "bootbox-" + className,
 | |
|       buttons: createLabels.apply(null, labels)
 | |
|     };
 | |
| 
 | |
|     // ensure the buttons properties generated, *after* merging
 | |
|     // with user args are still valid against the supplied labels
 | |
|     return validateButtons(
 | |
|       // merge the generated base properties with user supplied arguments
 | |
|       mergeArguments(
 | |
|         baseOptions,
 | |
|         args,
 | |
|         // if args.length > 1, properties specify how each arg maps to an object key
 | |
|         properties
 | |
|       ),
 | |
|       labels
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * from a given list of arguments return a suitable object of button labels
 | |
|    * all this does is normalise the given labels and translate them where possible
 | |
|    * e.g. "ok", "confirm" -> { ok: "OK, cancel: "Annuleren" }
 | |
|    */
 | |
|   function createLabels() {
 | |
|     var buttons = {};
 | |
| 
 | |
|     for (var i = 0, j = arguments.length; i < j; i++) {
 | |
|       var argument = arguments[i];
 | |
|       var key = argument.toLowerCase();
 | |
|       var value = argument.toUpperCase();
 | |
| 
 | |
|       buttons[key] = {
 | |
|         label: _t(value)
 | |
|       };
 | |
|     }
 | |
| 
 | |
|     return buttons;
 | |
|   }
 | |
| 
 | |
|   function validateButtons(options, buttons) {
 | |
|     var allowedButtons = {};
 | |
|     each(buttons, function(key, value) {
 | |
|       allowedButtons[value] = true;
 | |
|     });
 | |
| 
 | |
|     each(options.buttons, function(key) {
 | |
|       if (allowedButtons[key] === undefined) {
 | |
|         throw new Error("button key " + key + " is not allowed (options are " + buttons.join("\n") + ")");
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     return options;
 | |
|   }
 | |
| 
 | |
|   exports.alert = function() {
 | |
|     var options;
 | |
| 
 | |
|     options = mergeDialogOptions("alert", ["ok"], ["message", "callback"], arguments);
 | |
| 
 | |
|     if (options.callback && !$.isFunction(options.callback)) {
 | |
|       throw new Error("alert requires callback property to be a function when provided");
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * overrides
 | |
|      */
 | |
|     options.buttons.ok.callback = options.onEscape = function() {
 | |
|       if ($.isFunction(options.callback)) {
 | |
|         return options.callback.call(this);
 | |
|       }
 | |
|       return true;
 | |
|     };
 | |
| 
 | |
|     return exports.dialog(options);
 | |
|   };
 | |
| 
 | |
|   exports.confirm = function() {
 | |
|     var options;
 | |
| 
 | |
|     options = mergeDialogOptions("confirm", ["cancel", "confirm"], ["message", "callback"], arguments);
 | |
| 
 | |
|     /**
 | |
|      * overrides; undo anything the user tried to set they shouldn't have
 | |
|      */
 | |
|     options.buttons.cancel.callback = options.onEscape = function() {
 | |
|       return options.callback.call(this, false);
 | |
|     };
 | |
| 
 | |
|     options.buttons.confirm.callback = function() {
 | |
|       return options.callback.call(this, true);
 | |
|     };
 | |
| 
 | |
|     // confirm specific validation
 | |
|     if (!$.isFunction(options.callback)) {
 | |
|       throw new Error("confirm requires a callback");
 | |
|     }
 | |
| 
 | |
|     return exports.dialog(options);
 | |
|   };
 | |
| 
 | |
|   exports.prompt = function() {
 | |
|     var options;
 | |
|     var defaults;
 | |
|     var dialog;
 | |
|     var form;
 | |
|     var input;
 | |
|     var shouldShow;
 | |
|     var inputOptions;
 | |
| 
 | |
|     // we have to create our form first otherwise
 | |
|     // its value is undefined when gearing up our options
 | |
|     // @TODO this could be solved by allowing message to
 | |
|     // be a function instead...
 | |
|     form = $(templates.form);
 | |
| 
 | |
|     // prompt defaults are more complex than others in that
 | |
|     // users can override more defaults
 | |
|     // @TODO I don't like that prompt has to do a lot of heavy
 | |
|     // lifting which mergeDialogOptions can *almost* support already
 | |
|     // just because of 'value' and 'inputType' - can we refactor?
 | |
|     defaults = {
 | |
|       className: "bootbox-prompt",
 | |
|       buttons: createLabels("cancel", "confirm"),
 | |
|       value: "",
 | |
|       inputType: "text"
 | |
|     };
 | |
| 
 | |
|     options = validateButtons(
 | |
|       mergeArguments(defaults, arguments, ["title", "callback"]),
 | |
|       ["cancel", "confirm"]
 | |
|     );
 | |
| 
 | |
|     // capture the user's show value; we always set this to false before
 | |
|     // spawning the dialog to give us a chance to attach some handlers to
 | |
|     // it, but we need to make sure we respect a preference not to show it
 | |
|     shouldShow = (options.show === undefined) ? true : options.show;
 | |
| 
 | |
|     /**
 | |
|      * overrides; undo anything the user tried to set they shouldn't have
 | |
|      */
 | |
|     options.message = form;
 | |
| 
 | |
|     options.buttons.cancel.callback = options.onEscape = function() {
 | |
|       return options.callback.call(this, null);
 | |
|     };
 | |
| 
 | |
|     options.buttons.confirm.callback = function() {
 | |
|       var value;
 | |
| 
 | |
|       switch (options.inputType) {
 | |
|         case "text":
 | |
|         case "textarea":
 | |
|         case "email":
 | |
|         case "select":
 | |
|         case "date":
 | |
|         case "time":
 | |
|         case "number":
 | |
|         case "password":
 | |
|           value = input.val();
 | |
|           break;
 | |
| 
 | |
|         case "checkbox":
 | |
|           var checkedItems = input.find("input:checked");
 | |
| 
 | |
|           // we assume that checkboxes are always multiple,
 | |
|           // hence we default to an empty array
 | |
|           value = [];
 | |
| 
 | |
|           each(checkedItems, function(_, item) {
 | |
|             value.push($(item).val());
 | |
|           });
 | |
|           break;
 | |
|       }
 | |
| 
 | |
|       return options.callback.call(this, value);
 | |
|     };
 | |
| 
 | |
|     options.show = false;
 | |
| 
 | |
|     // prompt specific validation
 | |
|     if (!options.title) {
 | |
|       throw new Error("prompt requires a title");
 | |
|     }
 | |
| 
 | |
|     if (!$.isFunction(options.callback)) {
 | |
|       throw new Error("prompt requires a callback");
 | |
|     }
 | |
| 
 | |
|     if (!templates.inputs[options.inputType]) {
 | |
|       throw new Error("invalid prompt type");
 | |
|     }
 | |
| 
 | |
|     // create the input based on the supplied type
 | |
|     input = $(templates.inputs[options.inputType]);
 | |
| 
 | |
|     switch (options.inputType) {
 | |
|       case "text":
 | |
|       case "textarea":
 | |
|       case "email":
 | |
|       case "date":
 | |
|       case "time":
 | |
|       case "number":
 | |
|       case "password":
 | |
|         input.val(options.value);
 | |
|         break;
 | |
| 
 | |
|       case "select":
 | |
|         var groups = {};
 | |
|         inputOptions = options.inputOptions || [];
 | |
| 
 | |
|         if (!$.isArray(inputOptions)) {
 | |
|           throw new Error("Please pass an array of input options");
 | |
|         }
 | |
| 
 | |
|         if (!inputOptions.length) {
 | |
|           throw new Error("prompt with select requires options");
 | |
|         }
 | |
| 
 | |
|         each(inputOptions, function(_, option) {
 | |
| 
 | |
|           // assume the element to attach to is the input...
 | |
|           var elem = input;
 | |
| 
 | |
|           if (option.value === undefined || option.text === undefined) {
 | |
|             throw new Error("given options in wrong format");
 | |
|           }
 | |
| 
 | |
|           // ... but override that element if this option sits in a group
 | |
| 
 | |
|           if (option.group) {
 | |
|             // initialise group if necessary
 | |
|             if (!groups[option.group]) {
 | |
|               groups[option.group] = $("<optgroup/>").attr("label", option.group);
 | |
|             }
 | |
| 
 | |
|             elem = groups[option.group];
 | |
|           }
 | |
| 
 | |
|           elem.append("<option value='" + option.value + "'>" + option.text + "</option>");
 | |
|         });
 | |
| 
 | |
|         each(groups, function(_, group) {
 | |
|           input.append(group);
 | |
|         });
 | |
| 
 | |
|         // safe to set a select's value as per a normal input
 | |
|         input.val(options.value);
 | |
|         break;
 | |
| 
 | |
|       case "checkbox":
 | |
|         var values   = $.isArray(options.value) ? options.value : [options.value];
 | |
|         inputOptions = options.inputOptions || [];
 | |
| 
 | |
|         if (!inputOptions.length) {
 | |
|           throw new Error("prompt with checkbox requires options");
 | |
|         }
 | |
| 
 | |
|         if (!inputOptions[0].value || !inputOptions[0].text) {
 | |
|           throw new Error("given options in wrong format");
 | |
|         }
 | |
| 
 | |
|         // checkboxes have to nest within a containing element, so
 | |
|         // they break the rules a bit and we end up re-assigning
 | |
|         // our 'input' element to this container instead
 | |
|         input = $("<div/>");
 | |
| 
 | |
|         each(inputOptions, function(_, option) {
 | |
|           var checkbox = $(templates.inputs[options.inputType]);
 | |
| 
 | |
|           checkbox.find("input").attr("value", option.value);
 | |
|           checkbox.find("label").append(option.text);
 | |
| 
 | |
|           // we've ensured values is an array so we can always iterate over it
 | |
|           each(values, function(_, value) {
 | |
|             if (value === option.value) {
 | |
|               checkbox.find("input").prop("checked", true);
 | |
|             }
 | |
|           });
 | |
| 
 | |
|           input.append(checkbox);
 | |
|         });
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     // @TODO provide an attributes option instead
 | |
|     // and simply map that as keys: vals
 | |
|     if (options.placeholder) {
 | |
|       input.attr("placeholder", options.placeholder);
 | |
|     }
 | |
| 
 | |
|     if (options.pattern) {
 | |
|       input.attr("pattern", options.pattern);
 | |
|     }
 | |
| 
 | |
|     if (options.maxlength) {
 | |
|       input.attr("maxlength", options.maxlength);
 | |
|     }
 | |
| 
 | |
|     // now place it in our form
 | |
|     form.append(input);
 | |
| 
 | |
|     form.on("submit", function(e) {
 | |
|       e.preventDefault();
 | |
|       // Fix for SammyJS (or similar JS routing library) hijacking the form post.
 | |
|       e.stopPropagation();
 | |
|       // @TODO can we actually click *the* button object instead?
 | |
|       // e.g. buttons.confirm.click() or similar
 | |
|       dialog.find(".btn-primary").click();
 | |
|     });
 | |
| 
 | |
|     dialog = exports.dialog(options);
 | |
| 
 | |
|     // clear the existing handler focusing the submit button...
 | |
|     dialog.off("shown.bs.modal");
 | |
| 
 | |
|     // ...and replace it with one focusing our input, if possible
 | |
|     dialog.on("shown.bs.modal", function() {
 | |
|       // need the closure here since input isn't
 | |
|       // an object otherwise
 | |
|       input.focus();
 | |
|     });
 | |
| 
 | |
|     if (shouldShow === true) {
 | |
|       dialog.modal("show");
 | |
|     }
 | |
| 
 | |
|     return dialog;
 | |
|   };
 | |
| 
 | |
|   exports.dialog = function(options) {
 | |
|     options = sanitize(options);
 | |
| 
 | |
|     var dialog = $(templates.dialog);
 | |
|     var innerDialog = dialog.find(".modal-dialog");
 | |
|     var body = dialog.find(".modal-body");
 | |
|     var buttons = options.buttons;
 | |
|     var buttonStr = "";
 | |
|     var callbacks = {
 | |
|       onEscape: options.onEscape
 | |
|     };
 | |
| 
 | |
|     if ($.fn.modal === undefined) {
 | |
|       throw new Error(
 | |
|         "$.fn.modal is not defined; please double check you have included " +
 | |
|         "the Bootstrap JavaScript library. See http://getbootstrap.com/javascript/ " +
 | |
|         "for more details."
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     each(buttons, function(key, button) {
 | |
| 
 | |
|       // @TODO I don't like this string appending to itself; bit dirty. Needs reworking
 | |
|       // can we just build up button elements instead? slower but neater. Then button
 | |
|       // can just become a template too
 | |
|       buttonStr += "<button data-bb-handler='" + key + "' type='button' class='btn " + button.className + "'>" + button.label + "</button>";
 | |
|       callbacks[key] = button.callback;
 | |
|     });
 | |
| 
 | |
|     body.find(".bootbox-body").html(options.message);
 | |
| 
 | |
|     if (options.animate === true) {
 | |
|       dialog.addClass("fade");
 | |
|     }
 | |
| 
 | |
|     if (options.className) {
 | |
|       dialog.addClass(options.className);
 | |
|     }
 | |
| 
 | |
|     if (options.size === "large") {
 | |
|       innerDialog.addClass("modal-lg");
 | |
|     } else if (options.size === "small") {
 | |
|       innerDialog.addClass("modal-sm");
 | |
|     }
 | |
| 
 | |
|     if (options.title) {
 | |
|       body.before(templates.header);
 | |
|     }
 | |
| 
 | |
|     if (options.closeButton) {
 | |
|       var closeButton = $(templates.closeButton);
 | |
| 
 | |
|       if (options.title) {
 | |
|         dialog.find(".modal-header").prepend(closeButton);
 | |
|       } else {
 | |
|         closeButton.css("margin-top", "-10px").prependTo(body);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (options.title) {
 | |
|       dialog.find(".modal-title").html(options.title);
 | |
|     }
 | |
| 
 | |
|     if (buttonStr.length) {
 | |
|       body.after(templates.footer);
 | |
|       dialog.find(".modal-footer").html(buttonStr);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * Bootstrap event listeners; used handle extra
 | |
|      * setup & teardown required after the underlying
 | |
|      * modal has performed certain actions
 | |
|      */
 | |
| 
 | |
|     dialog.on("hidden.bs.modal", function(e) {
 | |
|       // ensure we don't accidentally intercept hidden events triggered
 | |
|       // by children of the current dialog. We shouldn't anymore now BS
 | |
|       // namespaces its events; but still worth doing
 | |
|       if (e.target === this) {
 | |
|         dialog.remove();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     /*
 | |
|     dialog.on("show.bs.modal", function() {
 | |
|       // sadly this doesn't work; show is called *just* before
 | |
|       // the backdrop is added so we'd need a setTimeout hack or
 | |
|       // otherwise... leaving in as would be nice
 | |
|       if (options.backdrop) {
 | |
|         dialog.next(".modal-backdrop").addClass("bootbox-backdrop");
 | |
|       }
 | |
|     });
 | |
|     */
 | |
| 
 | |
|     dialog.on("shown.bs.modal", function() {
 | |
|       dialog.find(".btn-primary:first").focus();
 | |
|     });
 | |
| 
 | |
|     /**
 | |
|      * Bootbox event listeners; experimental and may not last
 | |
|      * just an attempt to decouple some behaviours from their
 | |
|      * respective triggers
 | |
|      */
 | |
| 
 | |
|     if (options.backdrop !== "static") {
 | |
|       // A boolean true/false according to the Bootstrap docs
 | |
|       // should show a dialog the user can dismiss by clicking on
 | |
|       // the background.
 | |
|       // We always only ever pass static/false to the actual
 | |
|       // $.modal function because with `true` we can't trap
 | |
|       // this event (the .modal-backdrop swallows it)
 | |
|       // However, we still want to sort of respect true
 | |
|       // and invoke the escape mechanism instead
 | |
|       dialog.on("click.dismiss.bs.modal", function(e) {
 | |
|         // @NOTE: the target varies in >= 3.3.x releases since the modal backdrop
 | |
|         // moved *inside* the outer dialog rather than *alongside* it
 | |
|         if (dialog.children(".modal-backdrop").length) {
 | |
|           e.currentTarget = dialog.children(".modal-backdrop").get(0);
 | |
|         }
 | |
| 
 | |
|         if (e.target !== e.currentTarget) {
 | |
|           return;
 | |
|         }
 | |
| 
 | |
|         dialog.trigger("escape.close.bb");
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     dialog.on("escape.close.bb", function(e) {
 | |
|       if (callbacks.onEscape) {
 | |
|         processCallback(e, dialog, callbacks.onEscape);
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     /**
 | |
|      * Standard jQuery event listeners; used to handle user
 | |
|      * interaction with our dialog
 | |
|      */
 | |
| 
 | |
|     dialog.on("click", ".modal-footer button", function(e) {
 | |
|       var callbackKey = $(this).data("bb-handler");
 | |
| 
 | |
|       processCallback(e, dialog, callbacks[callbackKey]);
 | |
|     });
 | |
| 
 | |
|     dialog.on("click", ".bootbox-close-button", function(e) {
 | |
|       // onEscape might be falsy but that's fine; the fact is
 | |
|       // if the user has managed to click the close button we
 | |
|       // have to close the dialog, callback or not
 | |
|       processCallback(e, dialog, callbacks.onEscape);
 | |
|     });
 | |
| 
 | |
|     dialog.on("keyup", function(e) {
 | |
|       if (e.which === 27) {
 | |
|         dialog.trigger("escape.close.bb");
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     // the remainder of this method simply deals with adding our
 | |
|     // dialogent to the DOM, augmenting it with Bootstrap's modal
 | |
|     // functionality and then giving the resulting object back
 | |
|     // to our caller
 | |
| 
 | |
|     $(options.container).append(dialog);
 | |
| 
 | |
|     dialog.modal({
 | |
|       backdrop: options.backdrop ? "static": false,
 | |
|       keyboard: false,
 | |
|       show: false
 | |
|     });
 | |
| 
 | |
|     if (options.show) {
 | |
|       dialog.modal("show");
 | |
|     }
 | |
| 
 | |
|     // @TODO should we return the raw element here or should
 | |
|     // we wrap it in an object on which we can expose some neater
 | |
|     // methods, e.g. var d = bootbox.alert(); d.hide(); instead
 | |
|     // of d.modal("hide");
 | |
| 
 | |
|    /*
 | |
|     function BBDialog(elem) {
 | |
|       this.elem = elem;
 | |
|     }
 | |
| 
 | |
|     BBDialog.prototype = {
 | |
|       hide: function() {
 | |
|         return this.elem.modal("hide");
 | |
|       },
 | |
|       show: function() {
 | |
|         return this.elem.modal("show");
 | |
|       }
 | |
|     };
 | |
|     */
 | |
| 
 | |
|     return dialog;
 | |
| 
 | |
|   };
 | |
| 
 | |
|   exports.setDefaults = function() {
 | |
|     var values = {};
 | |
| 
 | |
|     if (arguments.length === 2) {
 | |
|       // allow passing of single key/value...
 | |
|       values[arguments[0]] = arguments[1];
 | |
|     } else {
 | |
|       // ... and as an object too
 | |
|       values = arguments[0];
 | |
|     }
 | |
| 
 | |
|     $.extend(defaults, values);
 | |
|   };
 | |
| 
 | |
|   exports.hideAll = function() {
 | |
|     $(".bootbox").modal("hide");
 | |
| 
 | |
|     return exports;
 | |
|   };
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * standard locales. Please add more according to ISO 639-1 standard. Multiple language variants are
 | |
|    * unlikely to be required. If this gets too large it can be split out into separate JS files.
 | |
|    */
 | |
|   var locales = {
 | |
|     bg_BG : {
 | |
|       OK      : "Ок",
 | |
|       CANCEL  : "Отказ",
 | |
|       CONFIRM : "Потвърждавам"
 | |
|     },
 | |
|     br : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Cancelar",
 | |
|       CONFIRM : "Sim"
 | |
|     },
 | |
|     cs : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Zrušit",
 | |
|       CONFIRM : "Potvrdit"
 | |
|     },
 | |
|     da : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Annuller",
 | |
|       CONFIRM : "Accepter"
 | |
|     },
 | |
|     de : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Abbrechen",
 | |
|       CONFIRM : "Akzeptieren"
 | |
|     },
 | |
|     el : {
 | |
|       OK      : "Εντάξει",
 | |
|       CANCEL  : "Ακύρωση",
 | |
|       CONFIRM : "Επιβεβαίωση"
 | |
|     },
 | |
|     en : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Cancel",
 | |
|       CONFIRM : "OK"
 | |
|     },
 | |
|     es : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Cancelar",
 | |
|       CONFIRM : "Aceptar"
 | |
|     },
 | |
|     et : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Katkesta",
 | |
|       CONFIRM : "OK"
 | |
|     },
 | |
|     fa : {
 | |
|       OK      : "قبول",
 | |
|       CANCEL  : "لغو",
 | |
|       CONFIRM : "تایید"
 | |
|     },
 | |
|     fi : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Peruuta",
 | |
|       CONFIRM : "OK"
 | |
|     },
 | |
|     fr : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Annuler",
 | |
|       CONFIRM : "D'accord"
 | |
|     },
 | |
|     he : {
 | |
|       OK      : "אישור",
 | |
|       CANCEL  : "ביטול",
 | |
|       CONFIRM : "אישור"
 | |
|     },
 | |
|     hu : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Mégsem",
 | |
|       CONFIRM : "Megerősít"
 | |
|     },
 | |
|     hr : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Odustani",
 | |
|       CONFIRM : "Potvrdi"
 | |
|     },
 | |
|     id : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Batal",
 | |
|       CONFIRM : "OK"
 | |
|     },
 | |
|     it : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Annulla",
 | |
|       CONFIRM : "Conferma"
 | |
|     },
 | |
|     ja : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "キャンセル",
 | |
|       CONFIRM : "確認"
 | |
|     },
 | |
|     lt : {
 | |
|       OK      : "Gerai",
 | |
|       CANCEL  : "Atšaukti",
 | |
|       CONFIRM : "Patvirtinti"
 | |
|     },
 | |
|     lv : {
 | |
|       OK      : "Labi",
 | |
|       CANCEL  : "Atcelt",
 | |
|       CONFIRM : "Apstiprināt"
 | |
|     },
 | |
|     nl : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Annuleren",
 | |
|       CONFIRM : "Accepteren"
 | |
|     },
 | |
|     no : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Avbryt",
 | |
|       CONFIRM : "OK"
 | |
|     },
 | |
|     pl : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Anuluj",
 | |
|       CONFIRM : "Potwierdź"
 | |
|     },
 | |
|     pt : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Cancelar",
 | |
|       CONFIRM : "Confirmar"
 | |
|     },
 | |
|     ru : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Отмена",
 | |
|       CONFIRM : "Применить"
 | |
|     },
 | |
|     sq : {
 | |
|       OK : "OK",
 | |
|       CANCEL : "Anulo",
 | |
|       CONFIRM : "Prano"
 | |
|     },
 | |
|     sv : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "Avbryt",
 | |
|       CONFIRM : "OK"
 | |
|     },
 | |
|     th : {
 | |
|       OK      : "ตกลง",
 | |
|       CANCEL  : "ยกเลิก",
 | |
|       CONFIRM : "ยืนยัน"
 | |
|     },
 | |
|     tr : {
 | |
|       OK      : "Tamam",
 | |
|       CANCEL  : "İptal",
 | |
|       CONFIRM : "Onayla"
 | |
|     },
 | |
|     zh_CN : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "取消",
 | |
|       CONFIRM : "确认"
 | |
|     },
 | |
|     zh_TW : {
 | |
|       OK      : "OK",
 | |
|       CANCEL  : "取消",
 | |
|       CONFIRM : "確認"
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   exports.addLocale = function(name, values) {
 | |
|     $.each(["OK", "CANCEL", "CONFIRM"], function(_, v) {
 | |
|       if (!values[v]) {
 | |
|         throw new Error("Please supply a translation for '" + v + "'");
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     locales[name] = {
 | |
|       OK: values.OK,
 | |
|       CANCEL: values.CANCEL,
 | |
|       CONFIRM: values.CONFIRM
 | |
|     };
 | |
| 
 | |
|     return exports;
 | |
|   };
 | |
| 
 | |
|   exports.removeLocale = function(name) {
 | |
|     delete locales[name];
 | |
| 
 | |
|     return exports;
 | |
|   };
 | |
| 
 | |
|   exports.setLocale = function(name) {
 | |
|     return exports.setDefaults("locale", name);
 | |
|   };
 | |
| 
 | |
|   exports.init = function(_$) {
 | |
|     return init(_$ || $);
 | |
|   };
 | |
| 
 | |
|   return exports;
 | |
| }));
 |