You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1034 lines
29 KiB

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