1/** 2 * bootbox.js [v4.4.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'>×</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: "en", 74 // show backdrop or not. Default to static so user has to interact with dialog 75 backdrop: "static", 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.call(dialog, 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 buttons = options.buttons; 152 153 total = getKeyLength(buttons); 154 155 each(buttons, function(key, button, index) { 156 157 if ($.isFunction(button)) { 158 // short form, assume value is our callback. Since button 159 // isn't an object it isn't a reference either so re-assign it 160 button = buttons[key] = { 161 callback: button 162 }; 163 } 164 165 // before any further checks make sure by now button is the correct type 166 if ($.type(button) !== "object") { 167 throw new Error("button with key " + key + " must be an object"); 168 } 169 170 if (!button.label) { 171 // the lack of an explicit label means we'll assume the key is good enough 172 button.label = key; 173 } 174 175 if (!button.className) { 176 if (total <= 2 && index === total-1) { 177 // always add a primary to the main option in a two-button dialog 178 button.className = "btn-primary"; 179 } else { 180 button.className = "btn-default"; 181 } 182 } 183 }); 184 185 return options; 186 } 187 188 /** 189 * map a flexible set of arguments into a single returned object 190 * if args.length is already one just return it, otherwise 191 * use the properties argument to map the unnamed args to 192 * object properties 193 * so in the latter case: 194 * mapArguments(["foo", $.noop], ["message", "callback"]) 195 * -> { message: "foo", callback: $.noop } 196 */ 197 function mapArguments(args, properties) { 198 var argn = args.length; 199 var options = {}; 200 201 if (argn < 1 || argn > 2) { 202 throw new Error("Invalid argument length"); 203 } 204 205 if (argn === 2 || typeof args[0] === "string") { 206 options[properties[0]] = args[0]; 207 options[properties[1]] = args[1]; 208 } else { 209 options = args[0]; 210 } 211 212 return options; 213 } 214 215 /** 216 * merge a set of default dialog options with user supplied arguments 217 */ 218 function mergeArguments(defaults, args, properties) { 219 return $.extend( 220 // deep merge 221 true, 222 // ensure the target is an empty, unreferenced object 223 {}, 224 // the base options object for this type of dialog (often just buttons) 225 defaults, 226 // args could be an object or array; if it's an array properties will 227 // map it to a proper options object 228 mapArguments( 229 args, 230 properties 231 ) 232 ); 233 } 234 235 /** 236 * this entry-level method makes heavy use of composition to take a simple 237 * range of inputs and return valid options suitable for passing to bootbox.dialog 238 */ 239 function mergeDialogOptions(className, labels, properties, args) { 240 // build up a base set of dialog properties 241 var baseOptions = { 242 className: "bootbox-" + className, 243 buttons: createLabels.apply(null, labels) 244 }; 245 246 // ensure the buttons properties generated, *after* merging 247 // with user args are still valid against the supplied labels 248 return validateButtons( 249 // merge the generated base properties with user supplied arguments 250 mergeArguments( 251 baseOptions, 252 args, 253 // if args.length > 1, properties specify how each arg maps to an object key 254 properties 255 ), 256 labels 257 ); 258 } 259 260 /** 261 * from a given list of arguments return a suitable object of button labels 262 * all this does is normalise the given labels and translate them where possible 263 * e.g. "ok", "confirm" -> { ok: "OK, cancel: "Annuleren" } 264 */ 265 function createLabels() { 266 var buttons = {}; 267 268 for (var i = 0, j = arguments.length; i < j; i++) { 269 var argument = arguments[i]; 270 var key = argument.toLowerCase(); 271 var value = argument.toUpperCase(); 272 273 buttons[key] = { 274 label: _t(value) 275 }; 276 } 277 278 return buttons; 279 } 280 281 function validateButtons(options, buttons) { 282 var allowedButtons = {}; 283 each(buttons, function(key, value) { 284 allowedButtons[value] = true; 285 }); 286 287 each(options.buttons, function(key) { 288 if (allowedButtons[key] === undefined) { 289 throw new Error("button key " + key + " is not allowed (options are " + buttons.join("\n") + ")"); 290 } 291 }); 292 293 return options; 294 } 295 296 exports.alert = function() { 297 var options; 298 299 options = mergeDialogOptions("alert", ["ok"], ["message", "callback"], arguments); 300 301 if (options.callback && !$.isFunction(options.callback)) { 302 throw new Error("alert requires callback property to be a function when provided"); 303 } 304 305 /** 306 * overrides 307 */ 308 options.buttons.ok.callback = options.onEscape = function() { 309 if ($.isFunction(options.callback)) { 310 return options.callback.call(this); 311 } 312 return true; 313 }; 314 315 return exports.dialog(options); 316 }; 317 318 exports.confirm = function() { 319 var options; 320 321 options = mergeDialogOptions("confirm", ["cancel", "confirm"], ["message", "callback"], arguments); 322 323 /** 324 * overrides; undo anything the user tried to set they shouldn't have 325 */ 326 options.buttons.cancel.callback = options.onEscape = function() { 327 return options.callback.call(this, false); 328 }; 329 330 options.buttons.confirm.callback = function() { 331 return options.callback.call(this, true); 332 }; 333 334 // confirm specific validation 335 if (!$.isFunction(options.callback)) { 336 throw new Error("confirm requires a callback"); 337 } 338 339 return exports.dialog(options); 340 }; 341 342 exports.prompt = function() { 343 var options; 344 var defaults; 345 var dialog; 346 var form; 347 var input; 348 var shouldShow; 349 var inputOptions; 350 351 // we have to create our form first otherwise 352 // its value is undefined when gearing up our options 353 // @TODO this could be solved by allowing message to 354 // be a function instead... 355 form = $(templates.form); 356 357 // prompt defaults are more complex than others in that 358 // users can override more defaults 359 // @TODO I don't like that prompt has to do a lot of heavy 360 // lifting which mergeDialogOptions can *almost* support already 361 // just because of 'value' and 'inputType' - can we refactor? 362 defaults = { 363 className: "bootbox-prompt", 364 buttons: createLabels("cancel", "confirm"), 365 value: "", 366 inputType: "text" 367 }; 368 369 options = validateButtons( 370 mergeArguments(defaults, arguments, ["title", "callback"]), 371 ["cancel", "confirm"] 372 ); 373 374 // capture the user's show value;
374 we always set this to false before 375 // spawning the dialog to give us a chance to attach some handlers to 376 // it, but we need to make sure we respect a preference not to show it 377 shouldShow = (options.show === undefined) ? true : options.show; 378 379 /** 380 * overrides; undo anything the user tried to set they shouldn't have 381 */ 382 options.message = form; 383 384 options.buttons.cancel.callback = options.onEscape = function() { 385 return options.callback.call(this, null); 386 }; 387 388 options.buttons.confirm.callback = function() { 389 var value; 390 391 switch (options.inputType) { 392 case "text": 393 case "textarea": 394 case "email": 395 case "select": 396 case "date": 397 case "time": 398 case "number": 399 case "password": 400 value = input.val(); 401 break; 402 403 case "checkbox": 404 var checkedItems = input.find("input:checked"); 405 406 // we assume that checkboxes are always multiple, 407 // hence we default to an empty array 408 value = []; 409 410 each(checkedItems, function(_, item) { 411 value.push($(item).val()); 412 }); 413 break; 414 } 415 416 return options.callback.call(this, value); 417 }; 418 419 options.show = false; 420 421 // prompt specific validation 422 if (!options.title) { 423 throw new Error("prompt requires a title"); 424 } 425 426 if (!$.isFunction(options.callback)) { 427 throw new Error("prompt requires a callback"); 428 } 429 430 if (!templates.inputs[options.inputType]) { 431 throw new Error("invalid prompt type"); 432 } 433 434 // create the input based on the supplied type 435 input = $(templates.inputs[options.inputType]); 436 437 switch (options.inputType) { 438 case "text": 439 case "textarea": 440 case "email": 441 case "date": 442 case "time": 443 case "number": 444 case "password": 445 input.val(options.value); 446 break; 447 448 case "select": 449 var groups = {}; 450 inputOptions = options.inputOptions || []; 451 452 if (!$.isArray(inputOptions)) { 453 throw new Error("Please pass an array of input options"); 454 } 455 456 if (!inputOptions.length) { 457 throw new Error("prompt with select requires options"); 458 } 459 460 each(inputOptions, function(_, option) { 461 462 // assume the element to attach to is the input... 463 var elem = input; 464 465 if (option.value === undefined || option.text === undefined) { 466 throw new Error("given options in wrong format"); 467 } 468 469 // ... but override that element if this option sits in a group 470 471 if (option.group) { 472 // initialise group if necessary 473 if (!groups[option.group]) { 474 groups[option.group] = $("<optgroup/>").attr("label", option.group); 475 } 476 477 elem = groups[option.group]; 478 } 479 480 elem.append("<option value='" + option.value + "'>" + option.text + "</option>"); 481 }); 482 483 each(groups, function(_, group) { 484 input.append(group); 485 }); 486 487 // safe to set a select's value as per a normal input 488 input.val(options.value); 489 break; 490 491 case "checkbox": 492 var values = $.isArray(options.value) ? options.value : [options.value]; 493 inputOptions = options.inputOptions || []; 494 495 if (!inputOptions.length) { 496 throw new Error("prompt with checkbox requires options"); 497 } 498 499 if (!inputOptions[0].value || !inputOptions[0].text) { 500 throw new Error("given options in wrong format"); 501 } 502 503 // checkboxes have to nest within a containing element, so 504 // they break the rules a bit and we end up re-assigning 505 // our 'input' element to this container instead 506 input = $("<div/>"); 507 508 each(inputOptions, function(_, option) { 509 var checkbox = $(templates.inputs[options.inputType]); 510 511 checkbox.find("input").attr("value", option.value); 512 checkbox.find("label").append(option.text); 513 514 // we've ensured values is an array so we can always iterate over it 515 each(values, function(_, value) { 516 if (value === option.value) { 517 checkbox.find("input").prop("checked", true); 518 } 519 }); 520 521 input.append(checkbox); 522 }); 523 break; 524 } 525 526 // @TODO provide an attributes option instead 527 // and simply map that as keys: vals 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 if (options.maxlength) { 537 input.attr("maxlength", options.maxlength); 538 } 539 540 // now place it in our form 541 form.append(input); 542 543 form.on("submit", function(e) { 544 e.preventDefault(); 545 // Fix for SammyJS (or similar JS routing library) hijacking the form post. 546 e.stopPropagation(); 547 // @TODO can we actually click *the* button object instead? 548 // e.g. buttons.confirm.click() or similar 549 dialog.find(".btn-primary").click(); 550 }); 551 552 dialog = exports.dialog(options); 553 554 // clear the existing handler focusing the submit button... 555 dialog.off("shown.bs.modal"); 556 557 // ...and replace it with one focusing our input, if possible 558 dialog.on("shown.bs.modal", function() { 559 // need the closure here since input isn't 560 // an object otherwise 561 input.focus(); 562 }); 563 564 if (shouldShow === true) { 565 dialog.modal("show"); 566 } 567 568 return dialog; 569 }; 570 571 exports.dialog = function(options) { 572 options = sanitize(options); 573 574 var dialog = $(templates.dialog);
575 var innerDialog = dialog.find(".modal-dialog"); 576 var body = dialog.find(".modal-body"); 577 var buttons = options.buttons; 578 var buttonStr = ""; 579 var callbacks = { 580 onEscape: options.onEscape 581 }; 582 583 if ($.fn.modal === undefined) { 584 throw new Error( 585 "$.fn.modal is not defined; please double check you have included " + 586 "the Bootstrap JavaScript library. See http://getbootstrap.com/javascript/ " + 587 "for more details." 588 ); 589 } 590 591 each(buttons, function(key, button) { 592 593 // @TODO I don't like this string appending to itself; bit dirty. Needs reworking 594 // can we just build up button elements instead? slower but neater. Then button 595 // can just become a template too 596 buttonStr += "<button data-bb-handler='" + key + "' type='button' class='btn " + button.className + "'>" + button.label + "</button>"; 597 callbacks[key] = button.callback; 598 }); 599 600 body.find(".bootbox-body").html(options.message); 601 602 if (options.animate === true) { 603 dialog.addClass("fade"); 604 } 605 606 if (options.className) { 607 dialog.addClass(options.className); 608 } 609 610 if (options.size === "large") { 611 innerDialog.addClass("modal-lg"); 612 } else if (options.size === "small") { 613 innerDialog.addClass("modal-sm"); 614 } 615 616 if (options.title) { 617 body.before(templates.header); 618 } 619 620 if (options.closeButton) { 621 var closeButton = $(templates.closeButton); 622 623 if (options.title) { 624 dialog.find(".modal-header").prepend(closeButton); 625 } else { 626 closeButton.css("margin-top", "-10px").prependTo(body); 627 } 628 } 629 630 if (options.title) { 631 dialog.find(".modal-title").html(options.title); 632 } 633 634 if (buttonStr.length) { 635 body.after(templates.footer); 636 dialog.find(".modal-footer").html(buttonStr); 637 } 638 639 640 /** 641 * Bootstrap event listeners; used handle extra 642 * setup & teardown required after the underlying 643 * modal has performed certain actions 644 */ 645 646 dialog.on("hidden.bs.modal", function(e) { 647 // ensure we don't accidentally intercept hidden events triggered 648 // by children of the current dialog. We shouldn't anymore now BS 649 // namespaces its events; but still worth doing 650 if (e.target === this) { 651 dialog.remove(); 652 } 653 }); 654 655 /* 656 dialog.on("show.bs.modal", function() { 657 // sadly this doesn't work; show is called *just* before 658 // the backdrop is added so we'd need a setTimeout hack or 659 // otherwise... leaving in as would be nice 660 if (options.backdrop) { 661 dialog.next(".modal-backdrop").addClass("bootbox-backdrop"); 662 } 663 }); 664 */ 665 666 dialog.on("shown.bs.modal", function() { 667 dialog.find(".btn-primary:first").focus(); 668 }); 669 670 /** 671 * Bootbox event listeners; experimental and may not last 672 * just an attempt to decouple some behaviours from their 673 * respective triggers 674 */ 675 676 if (options.backdrop !== "static") { 677 // A boolean true/false according to the Bootstrap docs 678 // should show a dialog the user can dismiss by clicking on 679 // the background. 680 // We always only ever pass static/false to the actual 681 // $.modal function because with `true` we can't trap 682 // this event (the .modal-backdrop swallows it) 683 // However, we still want to sort of respect true 684 // and invoke the escape mechanism instead 685 dialog.on("click.dismiss.bs.modal", function(e) { 686 // @NOTE: the target varies in >= 3.3.x releases since the modal backdrop 687 // moved *inside* the outer dialog rather than *alongside* it 688 if (dialog.children(".modal-backdrop").length) { 689 e.currentTarget = dialog.children(".modal-backdrop").get(0); 690 } 691 692 if (e.target !== e.currentTarget) { 693 return; 694 } 695 696 dialog.trigger("escape.close.bb"); 697 }); 698 } 699 700 dialog.on("escape.close.bb", function(e) { 701 if (callbacks.onEscape) { 702 processCallback(e, dialog, callbacks.onEscape); 703 } 704 }); 705 706 /** 707 * Standard jQuery event listeners; used to handle user 708 * interaction with our dialog 709 */ 710 711 dialog.on("click", ".modal-footer button", function(e) { 712 var callbackKey = $(this).data("bb-handler"); 713 714 processCallback(e, dialog, callbacks[callbackKey]); 715 }); 716 717 dialog.on("click", ".bootbox-close-button", function(e) { 718 // onEscape might be falsy but that's fine; the fact is 719 // if the user has managed to click the close button we 720 // have to close the dialog, callback or not 721 processCallback(e, dialog, callbacks.onEscape); 722 }); 723 724 dialog.on("keyup", function(e) { 725 if (e.which === 27) { 726 dialog.trigger("escape.close.bb"); 727 } 728 }); 729 730 // the remainder of this method simply deals with adding our 731 // dialogent to the DOM, augmenting it with Bootstrap's modal 732 // functionality and then giving the resulting object back 733 // to our caller 734 735 $(options.container).append(dialog); 736 737 dialog.modal({ 738 backdrop: options.backdrop ? "static": false, 739 keyboard: false, 740 show: false 741 }); 742 743 if (options.show) { 744 dialog.modal("show"); 745 } 746 747 // @TODO should we return the raw element here or should 748 // we wrap it in an object on which we can expose some neater 749 // methods, e.g. var d = bootbox.alert(); d.hide(); instead 750 // of d.modal("hide"); 751 752 /* 753 function BBDialog(elem) { 754 this.elem = elem; 755 } 756 757 BBDialog.prototype = { 758 hide: function() { 759 return this.elem.modal("hide"); 760 }, 761 show: function() { 762 return this.elem.modal("show"); 763 } 764 }; 765 */ 766 767 return dialog; 768 769 }; 770 771 exports.setDefaults = function() { 772 var values = {}; 773 774 if (arguments.length === 2) { 775 // allow passing of single key/value... 776 values[arguments[0]] = arguments[1]; 777 } else { 778 // ... and as an object too 779 values = arguments[0]; 780 } 781 782 $.extend(defaults, values); 783 }; 784 785 exports.hideAll = function() { 786 $(".bootbox").modal("hide"); 787 788 return exports; 789 }; 790 791 792 /** 793 * standard locales. Please add more according to ISO 639-1 standard. Multiple language variants are 794 * unlikely to be required. If this gets too large it can be split out into separate JS files. 795 */ 796 var locales = { 797 bg_BG : { 798 OK : "Ðк", 799 CANCEL : "ÐÑказ", 800 CONFIRM : "ÐоÑвÑÑждавам" 801 }, 802 br : { 803 OK : "OK", 804 CANCEL : "Cancelar", 805 CONFIRM : "Sim" 806 }, 807 cs : { 808 OK : "OK", 809 CANCEL : "ZruÅ¡it", 810 CONFIRM : "Potvrdit" 811 }, 812 da : { 813 OK : "OK", 814 CANCEL : "Annuller", 815 CONFIRM : "Accepter" 816 }, 817 de : { 818 OK : "OK", 819 CANCEL : "Abbrechen", 820 CONFIRM : "Akzeptieren" 821 }, 822 el : { 823 OK : "ÎνÏάξει", 824 CANCEL : "ÎκÏÏÏÏη", 825 CONFIRM : "ÎÏιβεβαίÏÏη" 826 }, 827 en : { 828 OK : "OK", 829 CANCEL : "Cancel", 830 CONFIRM : "OK" 831 }, 832 es : { 833 OK : "OK", 834 CANCEL : "Cancelar", 835 CONFIRM : "Aceptar" 836 }, 837 et : { 838 OK : "OK", 839 CANCEL : "Katkesta", 840 CONFIRM : "OK" 841 }, 842 fa : { 843 OK : "ÙØ¨ÙÙ", 844 CANCEL : "ÙØºÙ", 845 CONFIRM : "تاÛÛØ¯" 846 }, 847 fi : { 848 OK : "OK", 849 CANCEL : "Peruuta", 850 CONFIRM : "OK" 851 }, 852 fr : { 853 OK : "OK", 854 CANCEL : "Annuler", 855 CONFIRM : "D'accord" 856 }, 857 he : { 858 OK : "××ש×ר", 859 CANCEL : "×××××", 860 CONFIRM : "××ש×ר" 861 }, 862 hu : { 863 OK : "OK", 864 CANCEL : "Mégsem", 865 CONFIRM : "MegerÅsÃt" 866 }, 867 hr : { 868 OK : "OK", 869 CANCEL : "Odustani", 870 CONFIRM : "Potvrdi" 871 }, 872 id : { 873 OK : "OK", 874 CANCEL : "Batal", 875 CONFIRM : "OK" 876 }, 877 it : { 878 OK : "OK", 879 CANCEL : "Annulla", 880 CONFIRM : "Conferma" 881 }, 882 ja : { 883 OK : "OK", 884 CANCEL : "ãã£ã³ã»ã«", 885 CONFIRM : "確èª" 886 }, 887 lt : { 888 OK : "Gerai", 889 CANCEL : "AtÅ¡aukti", 890 CONFIRM : "Patvirtinti" 891 }, 892 lv : { 893 OK : "Labi", 894 CANCEL : "Atcelt", 895 CONFIRM : "ApstiprinÄt" 896 }, 897 nl : { 898 OK : "OK", 899 CANCEL : "Annuleren", 900 CONFIRM : "Accepteren" 901 }, 902 no : { 903 OK : "OK", 904 CANCEL : "Avbryt", 905 CONFIRM : "OK" 906 }, 907 pl : { 908 OK : "OK", 909 CANCEL : "Anuluj", 910 CONFIRM : "Potwierdź" 911 }, 912 pt : { 913 OK : "OK", 914 CANCEL : "Cancelar", 915 CONFIRM : "Confirmar" 916 }, 917 ru : { 918 OK : "OK", 919 CANCEL : "ÐÑмена", 920 CONFIRM : "ÐÑимениÑÑ" 921 }, 922 sq : { 923 OK : "OK", 924 CANCEL : "Anulo", 925 CONFIRM : "Prano" 926 }, 927 sv : { 928 OK : "OK", 929 CANCEL : "Avbryt", 930 CONFIRM : "OK" 931 }, 932 th : { 933 OK : "à¸à¸à¸¥à¸", 934 CANCEL : "ยà¸à¹à¸¥à¸´à¸", 935 CONFIRM : "ยืà¸à¸¢à¸±à¸" 936 }, 937 tr : { 938 OK : "Tamam", 939 CANCEL : "İptal", 940 CONFIRM : "Onayla" 941 }, 942 zh_CN : { 943 OK : "OK", 944 CANCEL : "åæ¶", 945 CONFIRM : "确认" 946 }, 947 zh_TW : { 948 OK : "OK", 949 CANCEL : "åæ¶", 950 CONFIRM : "確èª" 951 } 952 }; 953 954 exports.addLocale = function(name, values) { 955 $.each(["OK", "CANCEL", "CONFIRM"], function(_, v) { 956 if (!values[v]) { 957 throw new Error("Please supply a translation for '" + v + "'"); 958 } 959 }); 960 961 locales[name] = { 962 OK: values.OK, 963 CANCEL: values.CANCEL, 964 CONFIRM: values.CONFIRM 965 }; 966 967 return exports; 968 }; 969 970 exports.removeLocale = function(name) { 971 delete locales[name]; 972 973 return exports; 974 }; 975 976 exports.setLocale = function(name) { 977 return exports.setDefaults("locale", name); 978 }; 979 980 exports.init = function(_$) { 981 return init(_$ || $); 982 }; 983 984 return exports; 985}));
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.