PageSourceSearch

https://extranet.fcc.org.br/extranet/js/bootbox.js

js fcc.org.br collected 2026-09-24 09:01:23 UTC 23,905 bytes, 894 lines download raw bytes

1/**
2 * bootbox.js [v4.3.0]
3 *
4 * http://bootboxjs.com/license.txt
5 */
6
7// @see https://github.com/makeusabrew/bootbox/issues/180
8// @see https://github.com/makeusabrew/bootbox/issues/186
9(function (root, factory) {
10
11  "use strict";
12  if (typeof define === "function" && define.amd) {
13    // AMD. Register as an anonymous module.
14    define(["jquery"], factory);
15  } else if (typeof exports === "object") {
16    // Node. Does not work with strict CommonJS, but
17    // only CommonJS-like environments that support module.exports,
18    // like Node.
19    module.exports = factory(require("jquery"));
20  } else {
21    // Browser globals (root is window)
22    root.bootbox = factory(root.jQuery);
23  }
24
25}(this, function init($, undefined) {
26
27  "use strict";
28
29  // the base DOM structure needed to create a modal
30  var templates = {
31    dialog:
32      "<div class='bootbox modal' tabindex='-1' role='dialog'>" +
33        "<div class='modal-dialog'>" +
34          "<div class='modal-content'>" +
35            "<div class='modal-body'><div class='bootbox-body'></div></div>" +
36          "</div>" +
37        "</div>" +
38      "</div>",
39    header:
40      "<div class='modal-header'>" +
41        "<h4 class='modal-title'></h4>" +
42      "</div>",
43    footer:
44      "<div class='modal-footer'></div>",
45    closeButton:
46      "<button type='button' class='bootbox-close-button close' data-dismiss='modal' aria-hidden='true'>&times;</button>",
47    form:
48      "<form class='bootbox-form'></form>",
49    inputs: {
50      text:
51        "<input class='bootbox-input bootbox-input-text form-control' autocomplete=off type=text />",
52      textarea:
53        "<textarea class='bootbox-input bootbox-input-textarea form-control'></textarea>",
54      email:
55        "<input class='bootbox-input bootbox-input-email form-control' autocomplete='off' type='email' />",
56      select:
57        "<select class='bootbox-input bootbox-input-select form-control'></select>",
58      checkbox:
59        "<div class='checkbox'><label>
59<input class='bootbox-input bootbox-input-checkbox' type='checkbox' /></label></div>",
60      date:
61        "<input class='bootbox-input bootbox-input-date form-control' autocomplete=off type='date' />",
62      time:
63        "<input class='bootbox-input bootbox-input-time form-control' autocomplete=off type='time' />",
64      number:
65        "<input class='bootbox-input bootbox-input-number form-control' autocomplete=off type='number' />",
66      password:
67        "<input class='bootbox-input bootbox-input-password form-control' autocomplete='off' type='password' />"
68    }
69  };
70
71  var defaults = {
72    // default language
73    locale: "br",
74    // show backdrop or not
75    backdrop: true,
76    // animate the modal in/out
77    animate: true,
78    // additional class string applied to the top level dialog
79    className: null,
80    // whether or not to include a close button
81    closeButton: true,
82    // show the dialog immediately by default
83    show: true,
84    // dialog container
85    container: "body"
86  };
87
88  // our public object; augmented after our private API
89  var exports = {};
90
91  /**
92   * @private
93   */
94  function _t(key) {
95    var locale = locales[defaults.locale];
96    return locale ? locale[key] : locales.en[key];
97  }
98
99  function processCallback(e, dialog, callback) {
100    e.stopPropagation();
101    e.preventDefault();
102
103    // by default we assume a callback will get rid of the dialog,
104    // although it is given the opportunity to override this
105
106    // so, if the callback can be invoked and it *explicitly returns false*
107    // then we'll set a flag to keep the dialog active...
108    var preserveDialog = $.isFunction(callback) && callback(e) === false;
109
110    // ... otherwise we'll bin it
111    if (!preserveDialog) {
112      dialog.modal("hide");
113    }
114  }
115
116  function getKeyLength(obj) {
117    // @TODO defer to Object.keys(x).length if available?
118    var k, t = 0;
119    for (k in obj) {
120      t ++;
121    }
122    return t;
123  }
124
125  function each(collection, iterator) {
126    var index = 0;
127    $.each(collection, function(key, value) {
128      iterator(key, value, index++);
129    });
130  }
131
132  function sanitize(options) {
133    var buttons;
134    var total;
135
136    if (typeof options !== "object") {
137      throw new Error("Please supply an object of options");
138    }
139
140    if (!options.message) {
141      throw new Error("Please specify a message");
142    }
143
144    // make sure any supplied options take precedence over defaults
145    options = $.extend({}, defaults, options);
146
147    if (!options.buttons) {
148      options.buttons = {};
149    }
150
151    // we only support Bootstrap's "static" and false backdrop args
152    // supporting true would mean you could dismiss the dialog without
153    // explicitly interacting with it
154    options.backdrop = options.backdrop ? "static" : false;
155
156    buttons = options.buttons;
157
158    total = getKeyLength(buttons);
159
160    each(buttons, function(key, button, index) {
161
162      if ($.isFunction(button)) {
163        // short form, assume value is our callback. Since button
164        // isn't an object it isn't a reference either so re-assign it
165        button = buttons[key] = {
166          callback: button
167        };
168      }
169
170      // before any further checks make sure by now button is the correct type
171      if ($.type(button) !== "object") {
172        throw new Error("button with key " + key + " must be an object");
173      }
174
175      if (!button.label) {
176        // the lack of an explicit label means we'll assume the key is good enough
177        button.label = key;
178      }
179
180      if (!button.className) {
181        if (total <= 2 && index === total-1) {
182          // always add a primary to the main option in a two-button dialog
183          button.className = "btn-primary";
184        } else {
185          button.className = "btn-default";
186        }
187      }
188    });
189
190    return options;
191  }
192
193  /**
194   * map a flexible set of arguments into a single returned object
195   * if args.length is already one just return it, otherwise
196   * use the properties argument to map the unnamed args to
197   * object properties
198   * so in the latter case:
199   * mapArguments(["foo", $.noop], ["message", "callback"])
200   * -> { message: "foo", callback: $.noop }
201   */
202  function mapArguments(args, properties) {
203    var argn = args.length;
204    var options = {};
205
206    if (argn < 1 || argn > 2) {
207      throw new Error("Invalid argument length");
208    }
209
210    if (argn === 2 || typeof args[0] === "string") {
211      options[properties[0]] = args[0];
212      options[properties[1]] = args[1];
213    } else {
214      options = args[0];
215    }
216
217    return options;
218  }
219
220  /**
221   * merge a set of default dialog options with user supplied arguments
222   */
223  function mergeArguments(defaults, args, properties) {
224    return $.extend(
225      // deep merge
226      true,
227      // ensure the target is an empty, unreferenced object
228      {},
229      // the base options object for this type of dialog (often just buttons)
230      defaults,
231      // args could be an object or array; if it's an array properties will
232      // map it to a proper options object
233      mapArguments(
234        args,
235        properties
236      )
237    );
238  }
239
240  /**
241   * this entry-level method makes heavy use of composition to take a simple
242   * range of inputs and return valid options suitable for passing to bootbox.dialog
243   */
244  function mergeDialogOptions(className, labels, properties, args) {
245    //  build up a base set of dialog properties
246    var baseOptions = {
247      className: "bootbox-" + className,
248      buttons: createLabels.apply(null, labels)
249    };
250
251    // ensure the buttons properties generated, *after* merging
252    // with user args are still valid against the supplied labels
253    return validateButtons(
254      // merge the generated base properties with user supplied arguments
255      mergeArguments(
256        baseOptions,
257        args,
258        // if args.length > 1, properties specify how each arg maps to an object key
259        properties
260      ),
261      labels
262    );
263  }
264
265  /**
266   * from a given list of arguments return a suitable object of button labels
267   * all this does is normalise the given labels and translate them where possible
268   * e.g. "ok", "confirm" -> { ok: "OK, cancel: "Annuleren" }
269   */
270  function createLabels() {
271    var buttons = {};
272
273    for (var i = 0, j = arguments.length; i < j; i++) {
274      var argument = arguments[i];
275      var key = argument.toLowerCase();
276      var value = argument.toUpperCase();
277
278      buttons[key] = {
279        label: _t(value)
280      };
281    }
282
283    return buttons;
284  }
285
286  function validateButtons(options, buttons) {
287    var allowedButtons = {};
288    each(buttons, function(key, value) {
289      allowedButtons[value] = true;
290    });
291
292    each(options.buttons, function(key) {
293      if (allowedButtons[key] === undefined) {
294        throw new Error("button key " + key + " is not allowed (options are " + buttons.join("\n") + ")");
295      }
296    });
297
298    return options;
299  }
300
301  exports.alert = function() {
302    var options;
303
304    options = mergeDialogOptions("alert", ["ok"], ["message", "callback"], arguments);
305
306    if (options.callback && !$.isFunction(options.callback)) {
307      throw new Error("alert requires callback property to be a function when provided");
308    }
309
310    /**
311     * overrides
312     */
313    options.buttons.ok.callback = options.onEscape = function() {
314      if ($.isFunction(options.callback)) {
315        return options.callback();
316      }
317      return true;
318    };
319
320    return exports.dialog(options);
321  };
322
323  exports.confirm = function() {
324    var options;
325
326    options = mergeDialogOptions("confirm", ["cancel", "confirm"], ["message", "callback"], arguments);
327
328    /**
329     * overrides; undo anything the user tried to set they shouldn't have
330     */
331    options.buttons.cancel.callback = options.onEscape = function() {
332      return options.callback(false);
333    };
334
335    options.buttons.confirm.callback = function() {
336      return options.callback(true);
337    };
338
339    // confirm specific validation
340    if (!$.isFunction(options.callback)) {
341      throw new Error("confirm requires a callback");
342    }
343
344    return exports.dialog(options);
345  };
346
347  exports.prompt = function() {
348    var options;
349    var defaults;
350    var dialog;
351    var form;
352    var input;
353    var shouldShow;
354    var inputOptions;
355
356    // we have to create our form first otherwise
357    // its value is undefined when gearing up our options
358    // @TODO this could be solved by allowing message to
359    // be a function instead...
360    form = $(templates.form);
361
362    // prompt defaults are more complex than others in that
363    // users can override more defaults
364    // @TODO I don't like that prompt has to do a lot of heavy
365    // lifting which mergeDialogOptions can *almost* support already
366    // just because of 'value' and 'inputType' - can we refactor?
367    defaults = {
368      className: "bootbox-prompt",
369      buttons: createLabels("cancel", "confirm"),
370      value: "",
371      inputType: "text"
372    };
373
374    options = validateButtons(
375      mergeArguments(defaults, arguments, ["title", "callback"]),
376      ["cancel", "confirm"]
377    );
378
379    // capture the user's show value;
379 we always set this to false before
380    // spawning the dialog to give us a chance to attach some handlers to
381    // it, but we need to make sure we respect a preference not to show it
382    shouldShow = (options.show === undefined) ? true : options.show;
383
384    /**
385     * overrides; undo anything the user tried to set they shouldn't have
386     */
387    options.message = form;
388
389    options.buttons.cancel.callback = options.onEscape = function() {
390      return options.callback(null);
391    };
392
393    options.buttons.confirm.callback = function() {
394      var value;
395
396      switch (options.inputType) {
397        case "text":
398        case "textarea":
399        case "email":
400        case "select":
401        case "date":
402        case "time":
403        case "number":
404        case "password":
405          value = input.val();
406          break;
407
408        case "checkbox":
409          var checkedItems = input.find("input:checked");
410
411          // we assume that checkboxes are always multiple,
412          // hence we default to an empty array
413          value = [];
414
415          each(checkedItems, function(_, item) {
416            value.push($(item).val());
417          });
418          break;
419      }
420
421      return options.callback(value);
422    };
423
424    options.show = false;
425
426    // prompt specific validation
427    if (!options.title) {
428      throw new Error("prompt requires a title");
429    }
430
431    if (!$.isFunction(options.callback)) {
432      throw new Error("prompt requires a callback");
433    }
434
435    if (!templates.inputs[options.inputType]) {
436      throw new Error("invalid prompt type");
437    }
438
439    // create the input based on the supplied type
440    input = $(templates.inputs[options.inputType]);
441
442    switch (options.inputType) {
443      case "text":
444      case "textarea":
445      case "email":
446      case "date":
447      case "time":
448      case "number":
449      case "password":
450        input.val(options.value);
451        break;
452
453      case "select":
454        var groups = {};
455        inputOptions = options.inputOptions || [];
456
457        if (!inputOptions.length) {
458          throw new Error("prompt with select requires options");
459        }
460
461        each(inputOptions, function(_, option) {
462
463          // assume the element to attach to is the input...
464          var elem = input;
465
466          if (option.value === undefined || option.text === undefined) {
467            throw new Error("given options in wrong format");
468          }
469
470
471          // ... but override that element if this option sits in a group
472
473          if (option.group) {
474            // initialise group if necessary
475            if (!groups[option.group]) {
476              groups[option.group] = $("<optgroup/>").attr("label", option.group);
477            }
478
479            elem = groups[option.group];
480          }
481
482          elem.append("<option value='" + option.value + "'>" + option.text + "</option>");
483        });
484
485        each(groups, function(_, group) {
486          input.append(group);
487        });
488
489        // safe to set a select's value as per a normal input
490        input.val(options.value);
491        break;
492
493      case "checkbox":
494        var values   = $.isArray(options.value) ? options.value : [options.value];
495        inputOptions = options.inputOptions || [];
496
497        if (!inputOptions.length) {
498          throw new Error("prompt with checkbox requires options");
499        }
500
501        if (!inputOptions[0].value || !inputOptions[0].text) {
502          throw new Error("given options in wrong format");
503        }
504
505        // checkboxes have to nest within a containing element, so
506        // they break the rules a bit and we end up re-assigning
507        // our 'input' element to this container instead
508        input = $("<div/>");
509
510        each(inputOptions, function(_, option) {
511          var checkbox = $(templates.inputs[options.inputType]);
512
513          checkbox.find("input").attr("value", option.value);
514          checkbox.find("label").append(option.text);
515
516          // we've ensured values is an array so we can always iterate over it
517          each(values, function(_, value) {
518            if (value === option.value) {
519              checkbox.find("input").prop("checked", true);
520            }
521          });
522
523          input.append(checkbox);
524        });
525        break;
526    }
527
528    if (options.placeholder) {
529      input.attr("placeholder", options.placeholder);
530    }
531
532    if(options.pattern){
533      input.attr("pattern", options.pattern);
534    }
535
536    // now place it in our form
537    form.append(input);
538
539    form.on("submit", function(e) {
540      e.preventDefault();
541      // Fix for SammyJS (or similar JS routing library) hijacking the form post.
542      e.stopPropagation();
543      // @TODO can we actually click *the* button object instead?
544      // e.g. buttons.confirm.click() or similar
545      dialog.find(".btn-primary").click();
546    });
547
548    dialog = exports.dialog(options);
549
550    // clear the existing handler focusing the submit button...
551    dialog.off("shown.bs.modal");
552
553    // ...and replace it with one focusing our input, if possible
554    dialog.on("shown.bs.modal", function() {
555      input.focus();
556    });
557
558    if (shouldShow === true) {
559      dialog.modal("show");
560    }
561
562    return dialog;
563  };
564
565  exports.dialog = function(options) {
566    options = sanitize(options);
567
568    var dialog = $(templates.dialog);
569    var innerDialog = dialog.find(".modal-dialog");
570    var body = dialog.find(".modal-body");
571    var buttons = options.buttons;
572    var buttonStr = "";
573    var callbacks = {
574      onEscape: options.onEscape
575    };
576
577    each(buttons, function(key, button) {
578
579      // @TODO I don't like this string appending to itself; bit dirty. Needs reworking
580      // can we just build up button elements instead? slower but neater. Then button
581      // can just become a template too
582      buttonStr += "<button data-bb-handler='" + key + "' type='button' class='btn " + button.className + "'>" + button.label + "</button>";
583      callbacks[key] = button.callback;
584    });
585
586    body.find(".bootbox-body").html(options.message);
587
588    if (options.animate === true) {
589      dialog.addClass("fade");
590    }
591
592    if (options.className) {
593      dialog.addClass(options.className);
594    }
595
596    if (options.size === "large") {
597      innerDialog.addClass("modal-lg");
598    }
599
600    if (options.size === "small") {
601      innerDialog.addClass("modal-sm");
602    }
603
604    if (options.title) {
605      body.before(templates.header);
606    }
607
608    if (options.closeButton) {
609      var closeButton = $(templates.closeButton);
610
611      if (options.title) {
612        dialog.find(".modal-header").prepend(closeButton);
613      } else {
614        closeButton.css("margin-top", "-10px").prependTo(body);
615      }
616    }
617
618    if (options.title) {
619      dialog.find(".modal-title").html(options.title);
620    }
621
622    if (buttonStr.length) {
623      body.after(templates.footer);
624      dialog.find(".modal-footer").html(buttonStr);
625    }
626
627
628    /**
629     * Bootstrap event listeners; used handle extra
630     * setup & teardown required after the underlying
631     * modal has performed certain actions
632     */
633
634    dialog.on("hidden.bs.modal", function(e) {
635      // ensure we don't accidentally intercept hidden events triggered
636      // by children of the current dialog. We shouldn't anymore now BS
637      // namespaces its events; but still worth doing
638      if (e.target === this) {
639        dialog.remove();
640      }
641    });
642
643    /*
644    dialog.on("show.bs.modal", function() {
645      // sadly this doesn't work; show is called *just* before
646      // the backdrop is added so we'd need a setTimeout hack or
647      // otherwise... leaving in as would be nice
648      if (options.backdrop) {
649        dialog.next(".modal-backdrop").addClass("bootbox-backdrop");
650      }
651    });
652    */
653
654    dialog.on("shown.bs.modal", function() {
655      dialog.find(".btn-primary:first").focus();
656    });
657
658    /**
659     * Bootbox event listeners; experimental and may not last
660     * just an attempt to decouple some behaviours from their
661     * respective triggers
662     */
663
664    dialog.on("escape.close.bb", function(e) {
665      if (callbacks.onEscape) {
666        processCallback(e, dialog, callbacks.onEscape);
667      }
668    });
669
670    /**
671     * Standard jQuery event listeners; used to handle user
672     * interaction with our dialog
673     */
674
675    dialog.on("click", ".modal-footer button", function(e) {
676      var callbackKey = $(this).data("bb-handler");
677
678      processCallback(e, dialog, callbacks[callbackKey]);
679
680    });
681
682    dialog.on("click", ".bootbox-close-button", function(e) {
683      // onEscape might be falsy but that's fine; the fact is
684      // if the user has managed to click the close button we
685      // have to close the dialog, callback or not
686      processCallback(e, dialog, callbacks.onEscape);
687    });
688
689    dialog.on("keyup", function(e) {
690      if (e.which === 27) {
691        dialog.trigger("escape.close.bb");
692      }
693    });
694
695    // the remainder of this method simply deals with adding our
696    // dialogent to the DOM, augmenting it with Bootstrap's modal
697    // functionality and then giving the resulting object back
698    // to our caller
699
700    $(options.container).append(dialog);
701
702    dialog.modal({
703      backdrop: options.backdrop,
704      keyboard: false,
705      show: false
706    });
707
708    if (options.show) {
709      dialog.modal("show");
710    }
711
712    // @TODO should we return the raw element here or should
713    // we wrap it in an object on which we can expose some neater
714    // methods, e.g. var d = bootbox.alert(); d.hide(); instead
715    // of d.modal("hide");
716
717   /*
718    function BBDialog(elem) {
719      this.elem = elem;
720    }
721
722    BBDialog.prototype = {
723      hide: function() {
724        return this.elem.modal("hide");
725      },
726      show: function() {
727        return this.elem.modal("show");
728      }
729    };
730    */
731
732    return dialog;
733
734  };
735
736  exports.setDefaults = function() {
737    var values = {};
738
739    if (arguments.length === 2) {
740      // allow passing of single key/value...
741      values[arguments[0]] = arguments[1];
742    } else {
743      // ... and as an object too
744      values = arguments[0];
745    }
746
747    $.extend(defaults, values);
748  };
749
750  exports.hideAll = function() {
751    $(".bootbox").modal("hide");
752
753    return exports;
754  };
755
756
757  /**
758   * standard locales. Please add more according to ISO 639-1 standard. Multiple language variants are
759   * unlikely to be required. If this gets too large it can be split out into separate JS files.
760   */
761  var locales = {
762    br : {
763      OK      : "OK",
764      CANCEL  : "Não",
765      CONFIRM : "Sim"
766    },
767    cs : {
768      OK      : "OK",
769      CANCEL  : "Zrušit",
770      CONFIRM : "Potvrdit"
771    },
772    da : {
773      OK      : "OK",
774      CANCEL  : "Annuller",
775      CONFIRM : "Accepter"
776    },
777    de : {
778      OK      : "OK",
779      CANCEL  : "Abbrechen",
780      CONFIRM : "Akzeptieren"
781    },
782    el : {
783      OK      : "Εντάξει",
784      CANCEL  : "Ακύρωση",
785      CONFIRM : "Επιβεβαίωση"
786    },
787    en : {
788      OK      : "OK",
789      CANCEL  : "Cancel",
790      CONFIRM : "OK"
791    },
792    es : {
793      OK      : "OK",
794      CANCEL  : "Cancelar",
795      CONFIRM : "Aceptar"
796    },
797    et : {
798      OK      : "OK",
799      CANCEL  : "Katkesta",
800      CONFIRM : "OK"
801    },
802    fi : {
803      OK      : "OK",
804      CANCEL  : "Peruuta",
805      CONFIRM : "OK"
806    },
807    fr : {
808      OK      : "OK",
809      CANCEL  : "Annuler",
810      CONFIRM : "D'accord"
811    },
812    he : {
813      OK      : "אישור",
814      CANCEL  : "ביטול",
815      CONFIRM : "אישור"
816    },
817    id : {
818      OK      : "OK",
819      CANCEL  : "Batal",
820      CONFIRM : "OK"
821    },
822    it : {
823      OK      : "OK",
824      CANCEL  : "Annulla",
825      CONFIRM : "Conferma"
826    },
827    ja : {
828      OK      : "OK",
829      CANCEL  : "キャンセル",
830      CONFIRM : "確認"
831    },
832    lt : {
833      OK      : "Gerai",
834      CANCEL  : "Atšaukti",
835      CONFIRM : "Patvirtinti"
836    },
837    lv : {
838      OK      : "Labi",
839      CANCEL  : "Atcelt",
840      CONFIRM : "Apstiprināt"
841    },
842    nl : {
843      OK      : "OK",
844      CANCEL  : "Annuleren",
845      CONFIRM : "Accepteren"
846    },
847    no : {
848      OK      : "OK",
849      CANCEL  : "Avbryt",
850      CONFIRM : "OK"
851    },
852    pl : {
853      OK      : "OK",
854      CANCEL  : "Anuluj",
855      CONFIRM : "Potwierdź"
856    },
857    pt : {
858      OK      : "OK",
859      CANCEL  : "Cancelar",
860      CONFIRM : "Confirmar"
861    },
862    ru : {
863      OK      : "OK",
864      CANCEL  : "Отмена",
865      CONFIRM : "Применить"
866    },
867    sv : {
868      OK      : "OK",
869      CANCEL  : "Avbryt",
870      CONFIRM : "OK"
871    },
872    tr : {
873      OK      : "Tamam",
874      CANCEL  : "İptal",
875      CONFIRM : "Onayla"
876    },
877    zh_CN : {
878      OK      : "OK",
879      CANCEL  : "取消",
880      CONFIRM : "确认"
881    },
882    zh_TW : {
883      OK      : "OK",
884      CANCEL  : "取消",
885      CONFIRM : "確認"
886    }
887  };
888
889  exports.init = function(_$) {
890    return init(_$ || $);
891  };
892
893  return exports;
894}));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.