/** * bootbox.js v3.2.0 * * http://bootboxjs.com/license.txt */ var bootbox = window.bootbox || (function(document, $) { /*jshint scripturl:true sub:true */ var _locale = 'en', _defaultLocale = 'en', _animate = true, _backdrop = 'static', _defaultHref = 'javascript:;', _classes = '', _btnClasses = {}, _icons = {}, /* last var should always be the public object we'll return */ that = {}; /** * public API */ that.setLocale = function(locale) { for (var i in _locales) { if (i == locale) { _locale = locale; return; } } throw new Error('Invalid locale: '+locale); }; that.addLocale = function(locale, translations) { if (typeof _locales[locale] === 'undefined') { _locales[locale] = {}; } for (var str in translations) { _locales[locale][str] = translations[str]; } }; that.setIcons = function(icons) { _icons = icons; if (typeof _icons !== 'object' || _icons === null) { _icons = {}; } }; that.setBtnClasses = function(btnClasses) { _btnClasses = btnClasses; if (typeof _btnClasses !== 'object' || _btnClasses === null) { _btnClasses = {}; } }; that.alert = function(/*str, label, cb*/) { var str = "", label = _translate('OK'), cb = null; switch (arguments.length) { case 1: // no callback, default button label str = arguments[0]; break; case 2: // callback *or* custom button label dependent on type str = arguments[0]; if (typeof arguments[1] == 'function') { cb = arguments[1]; } else { label = arguments[1]; } break; case 3: // callback and custom button label str = arguments[0]; label = arguments[1]; cb = arguments[2]; break; default: throw new Error("Incorrect number of arguments: expected 1-3"); } return that.dialog(str, { // only button (ok) "label" : label, "icon" : _icons.OK, "class" : _btnClasses.OK, "callback": cb }, { // ensure that the escape key works; either invoking the user's // callback or true to just close the dialog "onEscape": cb || true }); }; that.confirm = function(/*str, labelCancel, labelOk, cb*/) { var str = "", labelCancel = _translate('CANCEL'), labelOk = _translate('CONFIRM'), cb = null; switch (arguments.length) { case 1: str = arguments[0]; break; case 2: str = arguments[0]; if (typeof arguments[1] == 'function') { cb = arguments[1]; } else { labelCancel = arguments[1]; } break; case 3: str = arguments[0]; labelCancel = arguments[1]; if (typeof arguments[2] == 'function') { cb = arguments[2]; } else { labelOk = arguments[2]; } break; case 4: str = arguments[0]; labelCancel = arguments[1]; labelOk = arguments[2]; cb = arguments[3]; break; default: throw new Error("Incorrect number of arguments: expected 1-4"); } var cancelCallback = function() { if (typeof cb === 'function') { return cb(false); } }; var confirmCallback = function() { if (typeof cb === 'function') { return cb(true); } }; return that.dialog(str, [{ // first button (cancel) "label" : labelCancel, "icon" : _icons.CANCEL, "class" : _btnClasses.CANCEL, "callback": cancelCallback }, { // second button (confirm) "label" : labelOk, "icon" : _icons.CONFIRM, "class" : _btnClasses.CONFIRM, "callback": confirmCallback }], { // escape key bindings "onEscape": cancelCallback }); }; that.prompt = function(/*str, labelCancel, labelOk, cb, defaultVal*/) { var str = "", labelCancel = _translate('CANCEL'), labelOk = _translate('CONFIRM'), cb = null, defaultVal = ""; switch (arguments.length) { case 1: str = arguments[0]; break; case 2: str = arguments[0]; if (typeof arguments[1] == 'function') { cb = arguments[1]; } else { labelCancel = arguments[1]; } break; case 3: str = arguments[0]; labelCancel = arguments[1]; if (typeof arguments[2] == 'function') { cb = arguments[2]; } else { labelOk = arguments[2]; } break; case 4: str = arguments[0]; labelCancel = arguments[1]; labelOk = arguments[2]; cb = arguments[3]; break; case 5: str = arguments[0]; labelCancel = arguments[1]; labelOk = arguments[2]; cb = arguments[3]; defaultVal = arguments[4]; break; default: throw new Error("Incorrect number of arguments: expected 1-5"); } var header = str; // let's keep a reference to the form object for later var form = $("
"); form.append(""); var cancelCallback = function() { if (typeof cb === 'function') { // yep, native prompts dismiss with null, whereas native // confirms dismiss with false... return cb(null); } }; var confirmCallback = function() { if (typeof cb === 'function') { return cb(form.find("input[type=text]").val()); } }; var div = that.dialog(form, [{ // first button (cancel) "label" : labelCancel, "icon" : _icons.CANCEL, "class" : _btnClasses.CANCEL, "callback": cancelCallback }, { // second button (confirm) "label" : labelOk, "icon" : _icons.CONFIRM, "class" : _btnClasses.CONFIRM, "callback": confirmCallback }], { // prompts need a few extra options "header" : header, // explicitly tell dialog NOT to show the dialog... "show" : false, "onEscape": cancelCallback }); // ... the reason the prompt needs to be hidden is because we need // to bind our own "shown" handler, after creating the modal but // before any show(n) events are triggered // @see https://github.com/makeusabrew/bootbox/issues/69 div.on("shown", function() { form.find("input[type=text]").focus(); // ensure that submitting the form (e.g. with the enter key) // replicates the behaviour of a normal prompt() form.on("submit", function(e) { e.preventDefault(); div.find(".btn-primary").click(); }); }); div.modal("show"); return div; }; that.dialog = function(str, handlers, options) { var buttons = "", callbacks = []; if (!options) { options = {}; } // check for single object and convert to array if necessary if (typeof handlers === 'undefined') { handlers = []; } else if (typeof handlers.length == 'undefined') { handlers = [handlers]; } var i = handlers.length; while (i--) { var label = null, href = null, _class = 'btn-default', icon = '', callback = null; if (typeof handlers[i]['label'] == 'undefined' && typeof handlers[i]['class'] == 'undefined' && typeof handlers[i]['callback'] == 'undefined') { // if we've got nothing we expect, check for condensed format var propCount = 0, // condensed will only match if this == 1 property = null; // save the last property we found // be nicer to count the properties without this, but don't think it's possible... for (var j in handlers[i]) { property = j; if (++propCount > 1) { // forget it, too many properties break; } } if (propCount == 1 && typeof handlers[i][j] == 'function') { // matches condensed format of label -> function handlers[i]['label'] = property; handlers[i]['callback'] = handlers[i][j]; } } if (typeof handlers[i]['callback']== 'function') { callback = handlers[i]['callback']; } if (handlers[i]['class']) { _class = handlers[i]['class']; } else if (i == handlers.length -1 && handlers.length <= 2) { // always add a primary to the main option in a two-button dialog _class = 'btn-primary'; } // See: https://github.com/makeusabrew/bootbox/pull/114 // Upgrade to official bootbox release when it gets merged. if (handlers[i]['link'] !== true) { _class = 'btn ' + _class; } if (handlers[i]['label']) { label = handlers[i]['label']; } else { label = "Option "+(i+1); } if (handlers[i]['icon']) { icon = " "; } if (handlers[i]['href']) { href = handlers[i]['href']; } else { href = _defaultHref; } buttons = buttons + ""+icon+""+label+""; callbacks[i] = callback; } // @see https://github.com/makeusabrew/bootbox/issues/46#issuecomment-8235302 // and https://github.com/twitter/bootstrap/issues/4474 // for an explanation of the inline overflow: hidden // @see https://github.com/twitter/bootstrap/issues/4854 // for an explanation of tabIndex=-1 var parts = [" "); var div = $(parts.join("\n")); // check whether we should fade in/out var shouldFade = (typeof options.animate === 'undefined') ? _animate : options.animate; if (shouldFade) { div.addClass("fade"); } var optionalClasses = (typeof options.classes === 'undefined') ? _classes : options.classes; if (optionalClasses) { div.addClass(optionalClasses); } // now we've built up the div properly we can inject the content whether it was a string or a jQuery object div.find(".modal-body").html(str); function onCancel(source) { // for now source is unused, but it will be in future var hideModal = null; if (typeof options.onEscape === 'function') { // @see https://github.com/makeusabrew/bootbox/issues/91 hideModal = options.onEscape(); } if (hideModal !== false) { div.modal('hide'); } } // hook into the modal's keyup trigger to check for the escape key div.on('keyup.dismiss.modal', function(e) { // any truthy value passed to onEscape will dismiss the dialog // as long as the onEscape function (if defined) doesn't prevent it if (e.which === 27 && options.onEscape !== false) { onCancel('escape'); } }); // handle close buttons too div.on('click', 'a.close', function(e) { e.preventDefault(); onCancel('close'); }); // well, *if* we have a primary - give the first dom element focus div.on('shown.bs.modal', function() { div.find("a.btn-primary:first").focus(); }); div.on('hidden.bs.modal', function() { div.remove(); }); // wire up button handlers div.on('click', '.modal-footer a', function(e) { var self = this; Ember.run(function() { var handler = $(self).data("handler"), cb = callbacks[handler], hideModal = null; // sort of @see https://github.com/makeusabrew/bootbox/pull/68 - heavily adapted // if we've got a custom href attribute, all bets are off if (typeof handler !== 'undefined' && typeof handlers[handler]['href'] !== 'undefined') { return; } e.preventDefault(); if (typeof cb === 'function') { hideModal = cb(e); } // the only way hideModal *will* be false is if a callback exists and // returns it as a value. in those situations, don't hide the dialog // @see https://github.com/makeusabrew/bootbox/pull/25 if (hideModal !== false) { div.modal("hide"); } }); }); // stick the modal right at the bottom of the main body out of the way (that.$body || $("body")).append(div); div.modal({ // unless explicitly overridden take whatever our default backdrop value is backdrop : (typeof options.backdrop === 'undefined') ? _backdrop : options.backdrop, // ignore bootstrap's keyboard options; we'll handle this ourselves (more fine-grained control) keyboard : false, // @ see https://github.com/makeusabrew/bootbox/issues/69 // we *never* want the modal to be shown before we can bind stuff to it // this method can also take a 'show' option, but we'll only use that // later if we need to show : false }); // @see https://github.com/makeusabrew/bootbox/issues/64 // @see https://github.com/makeusabrew/bootbox/issues/60 // ...caused by... // @see https://github.com/twitter/bootstrap/issues/4781 div.on("show", function(e) { $(document).off("focusin.modal"); }); if (typeof options.show === 'undefined' || options.show === true) { div.modal("show"); } return div; }; /** * #modal is deprecated in v3; it can still be used but no guarantees are * made - have never been truly convinced of its merit but perhaps just * needs a tidyup and some TLC */ that.modal = function(/*str, label, options*/) { var str; var label; var options; var defaultOptions = { "onEscape": null, "keyboard": true, "backdrop": _backdrop }; switch (arguments.length) { case 1: str = arguments[0]; break; case 2: str = arguments[0]; if (typeof arguments[1] == 'object') { options = arguments[1]; } else { label = arguments[1]; } break; case 3: str = arguments[0]; label = arguments[1]; options = arguments[2]; break; default: throw new Error("Incorrect number of arguments: expected 1-3"); } defaultOptions['header'] = label; if (typeof options == 'object') { options = $.extend(defaultOptions, options); } else { options = defaultOptions; } return that.dialog(str, [], options); }; that.hideAll = function() { $(".bootbox").modal("hide"); }; that.animate = function(animate) { _animate = animate; }; that.backdrop = function(backdrop) { _backdrop = backdrop; }; that.classes = function(classes) { _classes = classes; }; /** * private API */ /** * 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 = { 'br' : { OK : 'OK', CANCEL : 'Cancelar', CONFIRM : 'Sim' }, 'da' : { OK : 'OK', CANCEL : 'Annuller', CONFIRM : 'Accepter' }, 'de' : { OK : 'OK', CANCEL : 'Abbrechen', CONFIRM : 'Akzeptieren' }, 'en' : { OK : 'OK', CANCEL : 'Cancel', CONFIRM : 'OK' }, 'es' : { OK : 'OK', CANCEL : 'Cancelar', CONFIRM : 'Aceptar' }, 'fr' : { OK : 'OK', CANCEL : 'Annuler', CONFIRM : 'D\'accord' }, 'it' : { OK : 'OK', CANCEL : 'Annulla', CONFIRM : 'Conferma' }, 'nl' : { OK : 'OK', CANCEL : 'Annuleren', CONFIRM : 'Accepteren' }, 'pl' : { OK : 'OK', CANCEL : 'Anuluj', CONFIRM : 'Potwierdź' }, 'ru' : { OK : 'OK', CANCEL : 'Отмена', CONFIRM : 'Применить' }, 'zh_CN' : { OK : 'OK', CANCEL : '取消', CONFIRM : '确认' }, 'zh_TW' : { OK : 'OK', CANCEL : '取消', CONFIRM : '確認' } }; function _translate(str, locale) { // we assume if no target locale is probided then we should take it from current setting if (typeof locale === 'undefined') { locale = _locale; } if (typeof _locales[locale][str] === 'string') { return _locales[locale][str]; } // if we couldn't find a lookup then try and fallback to a default translation if (locale != _defaultLocale) { return _translate(str, _defaultLocale); } // if we can't do anything then bail out with whatever string was passed in - last resort return str; } return that; }(document, window.jQuery)); // @see https://github.com/makeusabrew/bootbox/issues/71 window.bootbox = bootbox;