bootstrap-dialog.js 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371
  1. /* global define */
  2. /* ================================================
  3. * Make use of Bootstrap's modal more monkey-friendly.
  4. *
  5. * For Bootstrap 3.
  6. *
  7. * javanoob@hotmail.com
  8. *
  9. * https://github.com/nakupanda/bootstrap3-dialog
  10. *
  11. * Licensed under The MIT License.
  12. * ================================================ */
  13. (function (root, factory) {
  14. "use strict";
  15. // CommonJS module is defined
  16. if (typeof module !== 'undefined' && module.exports) {
  17. var isNode = (typeof process !== "undefined");
  18. var isElectron = isNode && ('electron' in process.versions);
  19. if (isElectron) {
  20. root.BootstrapDialog = factory(root.jQuery);
  21. } else {
  22. module.exports = factory(require('jquery'), require('bootstrap'));
  23. }
  24. }
  25. // AMD module is defined
  26. else if (typeof define === "function" && define.amd) {
  27. define("bootstrap-dialog", ["jquery", "bootstrap"], function ($) {
  28. return factory($);
  29. });
  30. } else {
  31. // planted over the root!
  32. root.BootstrapDialog = factory(root.jQuery);
  33. }
  34. }(this, function ($) {
  35. "use strict";
  36. /* ================================================
  37. * Definition of BootstrapDialogModal.
  38. * Extend Bootstrap Modal and override some functions.
  39. * BootstrapDialogModal === Modified Modal.
  40. * ================================================ */
  41. var Modal = $.fn.modal.Constructor;
  42. var BootstrapDialogModal = function (element, options) {
  43. Modal.call(this, element, options);
  44. };
  45. BootstrapDialogModal.getModalVersion = function () {
  46. var version = null;
  47. if (typeof $.fn.modal.Constructor.VERSION === 'undefined') {
  48. version = 'v3.1';
  49. } else if (/3\.2\.\d+/.test($.fn.modal.Constructor.VERSION)) {
  50. version = 'v3.2';
  51. } else if (/3\.3\.[1,2]/.test($.fn.modal.Constructor.VERSION)) {
  52. version = 'v3.3'; // v3.3.1, v3.3.2
  53. } else {
  54. version = 'v3.3.4';
  55. }
  56. return version;
  57. };
  58. BootstrapDialogModal.ORIGINAL_BODY_PADDING = parseInt(($('body').css('padding-right') || 0), 10);
  59. BootstrapDialogModal.METHODS_TO_OVERRIDE = {};
  60. BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.1'] = {};
  61. BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.2'] = {
  62. hide: function (e) {
  63. if (e) {
  64. e.preventDefault();
  65. }
  66. e = $.Event('hide.bs.modal');
  67. this.$element.trigger(e);
  68. if (!this.isShown || e.isDefaultPrevented()) {
  69. return;
  70. }
  71. this.isShown = false;
  72. // Remove css class 'modal-open' when the last opened dialog is closing.
  73. var openedDialogs = this.getGlobalOpenedDialogs();
  74. if (openedDialogs.length === 0) {
  75. this.$body.removeClass('modal-open');
  76. }
  77. this.resetScrollbar();
  78. this.escape();
  79. $(document).off('focusin.bs.modal');
  80. this.$element
  81. .removeClass('in')
  82. .attr('aria-hidden', true)
  83. .off('click.dismiss.bs.modal');
  84. $.support.transition && this.$element.hasClass('fade') ?
  85. this.$element
  86. .one('bsTransitionEnd', $.proxy(this.hideModal, this))
  87. .emulateTransitionEnd(300) :
  88. this.hideModal();
  89. }
  90. };
  91. BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.3'] = {
  92. /**
  93. * Overrided.
  94. *
  95. * @returns {undefined}
  96. */
  97. setScrollbar: function () {
  98. var bodyPad = BootstrapDialogModal.ORIGINAL_BODY_PADDING;
  99. if (this.bodyIsOverflowing) {
  100. this.$body.css('padding-right', bodyPad + this.scrollbarWidth);
  101. }
  102. },
  103. /**
  104. * Overrided.
  105. *
  106. * @returns {undefined}
  107. */
  108. resetScrollbar: function () {
  109. var openedDialogs = this.getGlobalOpenedDialogs();
  110. if (openedDialogs.length === 0) {
  111. this.$body.css('padding-right', BootstrapDialogModal.ORIGINAL_BODY_PADDING);
  112. }
  113. },
  114. /**
  115. * Overrided.
  116. *
  117. * @returns {undefined}
  118. */
  119. hideModal: function () {
  120. this.$element.hide();
  121. this.backdrop($.proxy(function () {
  122. var openedDialogs = this.getGlobalOpenedDialogs();
  123. if (openedDialogs.length === 0) {
  124. this.$body.removeClass('modal-open');
  125. }
  126. this.resetAdjustments();
  127. this.resetScrollbar();
  128. this.$element.trigger('hidden.bs.modal');
  129. }, this));
  130. }
  131. };
  132. BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.3.4'] = $.extend({}, BootstrapDialogModal.METHODS_TO_OVERRIDE['v3.3']);
  133. BootstrapDialogModal.prototype = {
  134. constructor: BootstrapDialogModal,
  135. /**
  136. * New function, to get the dialogs that opened by BootstrapDialog.
  137. *
  138. * @returns {undefined}
  139. */
  140. getGlobalOpenedDialogs: function () {
  141. var openedDialogs = [];
  142. $.each(BootstrapDialog.dialogs, function (id, dialogInstance) {
  143. if (dialogInstance.isRealized() && dialogInstance.isOpened()) {
  144. openedDialogs.push(dialogInstance);
  145. }
  146. });
  147. return openedDialogs;
  148. }
  149. };
  150. // Add compatible methods.
  151. BootstrapDialogModal.prototype = $.extend(BootstrapDialogModal.prototype, Modal.prototype, BootstrapDialogModal.METHODS_TO_OVERRIDE[BootstrapDialogModal.getModalVersion()]);
  152. /* ================================================
  153. * Definition of BootstrapDialog.
  154. * ================================================ */
  155. var BootstrapDialog = function (options) {
  156. this.defaultOptions = $.extend(true, {
  157. id: BootstrapDialog.newGuid(),
  158. buttons: [],
  159. data: {},
  160. onshow: null,
  161. onshown: null,
  162. onhide: null,
  163. onhidden: null
  164. }, BootstrapDialog.defaultOptions);
  165. this.indexedButtons = {};
  166. this.registeredButtonHotkeys = {};
  167. this.draggableData = {
  168. isMouseDown: false,
  169. mouseOffset: {}
  170. };
  171. this.realized = false;
  172. this.opened = false;
  173. this.initOptions(options);
  174. this.holdThisInstance();
  175. };
  176. BootstrapDialog.BootstrapDialogModal = BootstrapDialogModal;
  177. /**
  178. * Some constants.
  179. */
  180. BootstrapDialog.NAMESPACE = 'bootstrap-dialog';
  181. BootstrapDialog.TYPE_DEFAULT = 'type-default';
  182. BootstrapDialog.TYPE_INFO = 'type-info';
  183. BootstrapDialog.TYPE_PRIMARY = 'type-primary';
  184. BootstrapDialog.TYPE_SUCCESS = 'type-success';
  185. BootstrapDialog.TYPE_WARNING = 'type-warning';
  186. BootstrapDialog.TYPE_DANGER = 'type-danger';
  187. BootstrapDialog.DEFAULT_TEXTS = {};
  188. BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_DEFAULT] = 'Information';
  189. BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_INFO] = 'Information';
  190. BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_PRIMARY] = 'Information';
  191. BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_SUCCESS] = 'Success';
  192. BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_WARNING] = 'Warning';
  193. BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_DANGER] = 'Danger';
  194. BootstrapDialog.DEFAULT_TEXTS['OK'] = 'OK';
  195. BootstrapDialog.DEFAULT_TEXTS['CANCEL'] = 'Cancel';
  196. BootstrapDialog.DEFAULT_TEXTS['CONFIRM'] = 'Confirmation';
  197. BootstrapDialog.SIZE_NORMAL = 'size-normal';
  198. BootstrapDialog.SIZE_SMALL = 'size-small';
  199. BootstrapDialog.SIZE_WIDE = 'size-wide'; // size-wide is equal to modal-lg
  200. BootstrapDialog.SIZE_LARGE = 'size-large';
  201. BootstrapDialog.BUTTON_SIZES = {};
  202. BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_NORMAL] = '';
  203. BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_SMALL] = '';
  204. BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_WIDE] = '';
  205. BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_LARGE] = 'btn-lg';
  206. BootstrapDialog.ICON_SPINNER = 'glyphicon glyphicon-asterisk';
  207. /**
  208. * Default options.
  209. */
  210. BootstrapDialog.defaultOptions = {
  211. type: BootstrapDialog.TYPE_PRIMARY,
  212. size: BootstrapDialog.SIZE_NORMAL,
  213. cssClass: '',
  214. title: null,
  215. message: null,
  216. nl2br: true,
  217. closable: true,
  218. closeByBackdrop: true,
  219. closeByKeyboard: true,
  220. closeIcon: '×',
  221. spinicon: BootstrapDialog.ICON_SPINNER,
  222. autodestroy: true,
  223. draggable: false,
  224. animate: true,
  225. description: '',
  226. tabindex: -1
  227. };
  228. /**
  229. * Config default options.
  230. */
  231. BootstrapDialog.configDefaultOptions = function (options) {
  232. BootstrapDialog.defaultOptions = $.extend(true, BootstrapDialog.defaultOptions, options);
  233. };
  234. /**
  235. * Open / Close all created dialogs all at once.
  236. */
  237. BootstrapDialog.dialogs = {};
  238. BootstrapDialog.openAll = function () {
  239. $.each(BootstrapDialog.dialogs, function (id, dialogInstance) {
  240. dialogInstance.open();
  241. });
  242. };
  243. BootstrapDialog.closeAll = function () {
  244. $.each(BootstrapDialog.dialogs, function (id, dialogInstance) {
  245. dialogInstance.close();
  246. });
  247. };
  248. /**
  249. * Get dialog instance by given id.
  250. *
  251. * @returns dialog instance
  252. */
  253. BootstrapDialog.getDialog = function (id) {
  254. var dialog = null;
  255. if (typeof BootstrapDialog.dialogs[id] !== 'undefined') {
  256. dialog = BootstrapDialog.dialogs[id];
  257. }
  258. return dialog;
  259. };
  260. /**
  261. * Set a dialog.
  262. *
  263. * @returns the dialog that has just been set.
  264. */
  265. BootstrapDialog.setDialog = function (dialog) {
  266. BootstrapDialog.dialogs[dialog.getId()] = dialog;
  267. return dialog;
  268. };
  269. /**
  270. * Alias of BootstrapDialog.setDialog(dialog)
  271. *
  272. * @param {type} dialog
  273. * @returns {unresolved}
  274. */
  275. BootstrapDialog.addDialog = function (dialog) {
  276. return BootstrapDialog.setDialog(dialog);
  277. };
  278. /**
  279. * Move focus to next visible dialog.
  280. */
  281. BootstrapDialog.moveFocus = function () {
  282. var lastDialogInstance = null;
  283. $.each(BootstrapDialog.dialogs, function (id, dialogInstance) {
  284. if (dialogInstance.isRealized() && dialogInstance.isOpened()) {
  285. lastDialogInstance = dialogInstance;
  286. }
  287. });
  288. if (lastDialogInstance !== null) {
  289. lastDialogInstance.getModal().focus();
  290. }
  291. };
  292. BootstrapDialog.METHODS_TO_OVERRIDE = {};
  293. BootstrapDialog.METHODS_TO_OVERRIDE['v3.1'] = {
  294. handleModalBackdropEvent: function () {
  295. this.getModal().on('click', {dialog: this}, function (event) {
  296. event.target === this && event.data.dialog.isClosable() && event.data.dialog.canCloseByBackdrop() && event.data.dialog.close();
  297. });
  298. return this;
  299. },
  300. /**
  301. * To make multiple opened dialogs look better.
  302. *
  303. * Will be removed in later version, after Bootstrap Modal >= 3.3.0, updating z-index is unnecessary.
  304. */
  305. updateZIndex: function () {
  306. if (this.isOpened()) {
  307. var zIndexBackdrop = 1040;
  308. var zIndexModal = 1050;
  309. var dialogCount = 0;
  310. $.each(BootstrapDialog.dialogs, function (dialogId, dialogInstance) {
  311. if (dialogInstance.isRealized() && dialogInstance.isOpened()) {
  312. dialogCount++;
  313. }
  314. });
  315. var $modal = this.getModal();
  316. var $backdrop = $modal.data('bs.modal').$backdrop;
  317. $modal.css('z-index', zIndexModal + (dialogCount - 1) * 20);
  318. $backdrop.css('z-index', zIndexBackdrop + (dialogCount - 1) * 20);
  319. }
  320. return this;
  321. },
  322. open: function () {
  323. !this.isRealized() && this.realize();
  324. this.getModal().modal('show');
  325. this.updateZIndex();
  326. return this;
  327. }
  328. };
  329. BootstrapDialog.METHODS_TO_OVERRIDE['v3.2'] = {
  330. handleModalBackdropEvent: BootstrapDialog.METHODS_TO_OVERRIDE['v3.1']['handleModalBackdropEvent'],
  331. updateZIndex: BootstrapDialog.METHODS_TO_OVERRIDE['v3.1']['updateZIndex'],
  332. open: BootstrapDialog.METHODS_TO_OVERRIDE['v3.1']['open']
  333. };
  334. BootstrapDialog.METHODS_TO_OVERRIDE['v3.3'] = {};
  335. BootstrapDialog.METHODS_TO_OVERRIDE['v3.3.4'] = $.extend({}, BootstrapDialog.METHODS_TO_OVERRIDE['v3.1']);
  336. BootstrapDialog.prototype = {
  337. constructor: BootstrapDialog,
  338. initOptions: function (options) {
  339. this.options = $.extend(true, this.defaultOptions, options);
  340. return this;
  341. },
  342. holdThisInstance: function () {
  343. BootstrapDialog.addDialog(this);
  344. return this;
  345. },
  346. initModalStuff: function () {
  347. this.setModal(this.createModal())
  348. .setModalDialog(this.createModalDialog())
  349. .setModalContent(this.createModalContent())
  350. .setModalHeader(this.createModalHeader())
  351. .setModalBody(this.createModalBody())
  352. .setModalFooter(this.createModalFooter());
  353. this.getModal().append(this.getModalDialog());
  354. this.getModalDialog().append(this.getModalContent());
  355. this.getModalContent()
  356. .append(this.getModalHeader())
  357. .append(this.getModalBody())
  358. .append(this.getModalFooter());
  359. return this;
  360. },
  361. createModal: function () {
  362. var $modal = $('<div class="modal" role="dialog" aria-hidden="true"></div>');
  363. $modal.prop('id', this.getId());
  364. $modal.attr('aria-labelledby', this.getId() + '_title');
  365. return $modal;
  366. },
  367. getModal: function () {
  368. return this.$modal;
  369. },
  370. setModal: function ($modal) {
  371. this.$modal = $modal;
  372. return this;
  373. },
  374. createModalDialog: function () {
  375. return $('<div class="modal-dialog"></div>');
  376. },
  377. getModalDialog: function () {
  378. return this.$modalDialog;
  379. },
  380. setModalDialog: function ($modalDialog) {
  381. this.$modalDialog = $modalDialog;
  382. return this;
  383. },
  384. createModalContent: function () {
  385. return $('<div class="modal-content"></div>');
  386. },
  387. getModalContent: function () {
  388. return this.$modalContent;
  389. },
  390. setModalContent: function ($modalContent) {
  391. this.$modalContent = $modalContent;
  392. return this;
  393. },
  394. createModalHeader: function () {
  395. return $('<div class="modal-header"></div>');
  396. },
  397. getModalHeader: function () {
  398. return this.$modalHeader;
  399. },
  400. setModalHeader: function ($modalHeader) {
  401. this.$modalHeader = $modalHeader;
  402. return this;
  403. },
  404. createModalBody: function () {
  405. return $('<div class="modal-body"></div>');
  406. },
  407. getModalBody: function () {
  408. return this.$modalBody;
  409. },
  410. setModalBody: function ($modalBody) {
  411. this.$modalBody = $modalBody;
  412. return this;
  413. },
  414. createModalFooter: function () {
  415. return $('<div class="modal-footer"></div>');
  416. },
  417. getModalFooter: function () {
  418. return this.$modalFooter;
  419. },
  420. setModalFooter: function ($modalFooter) {
  421. this.$modalFooter = $modalFooter;
  422. return this;
  423. },
  424. createDynamicContent: function (rawContent) {
  425. var content = null;
  426. if (typeof rawContent === 'function') {
  427. content = rawContent.call(rawContent, this);
  428. } else {
  429. content = rawContent;
  430. }
  431. if (typeof content === 'string') {
  432. content = this.formatStringContent(content);
  433. }
  434. return content;
  435. },
  436. formatStringContent: function (content) {
  437. if (this.options.nl2br) {
  438. return content.replace(/\r\n/g, '<br />').replace(/[\r\n]/g, '<br />');
  439. }
  440. return content;
  441. },
  442. setData: function (key, value) {
  443. this.options.data[key] = value;
  444. return this;
  445. },
  446. getData: function (key) {
  447. return this.options.data[key];
  448. },
  449. setId: function (id) {
  450. this.options.id = id;
  451. return this;
  452. },
  453. getId: function () {
  454. return this.options.id;
  455. },
  456. getType: function () {
  457. return this.options.type;
  458. },
  459. setType: function (type) {
  460. this.options.type = type;
  461. this.updateType();
  462. return this;
  463. },
  464. updateType: function () {
  465. if (this.isRealized()) {
  466. var types = [BootstrapDialog.TYPE_DEFAULT,
  467. BootstrapDialog.TYPE_INFO,
  468. BootstrapDialog.TYPE_PRIMARY,
  469. BootstrapDialog.TYPE_SUCCESS,
  470. BootstrapDialog.TYPE_WARNING,
  471. BootstrapDialog.TYPE_DANGER];
  472. this.getModal().removeClass(types.join(' ')).addClass(this.getType());
  473. }
  474. return this;
  475. },
  476. getSize: function () {
  477. return this.options.size;
  478. },
  479. setSize: function (size) {
  480. this.options.size = size;
  481. this.updateSize();
  482. return this;
  483. },
  484. updateSize: function () {
  485. if (this.isRealized()) {
  486. var dialog = this;
  487. // Dialog size
  488. this.getModal().removeClass(BootstrapDialog.SIZE_NORMAL)
  489. .removeClass(BootstrapDialog.SIZE_SMALL)
  490. .removeClass(BootstrapDialog.SIZE_WIDE)
  491. .removeClass(BootstrapDialog.SIZE_LARGE);
  492. this.getModal().addClass(this.getSize());
  493. // Smaller dialog.
  494. this.getModalDialog().removeClass('modal-sm');
  495. if (this.getSize() === BootstrapDialog.SIZE_SMALL) {
  496. this.getModalDialog().addClass('modal-sm');
  497. }
  498. // Wider dialog.
  499. this.getModalDialog().removeClass('modal-lg');
  500. if (this.getSize() === BootstrapDialog.SIZE_WIDE) {
  501. this.getModalDialog().addClass('modal-lg');
  502. }
  503. // Button size
  504. $.each(this.options.buttons, function (index, button) {
  505. var $button = dialog.getButton(button.id);
  506. var buttonSizes = ['btn-lg', 'btn-sm', 'btn-xs'];
  507. var sizeClassSpecified = false;
  508. if (typeof button['cssClass'] === 'string') {
  509. var btnClasses = button['cssClass'].split(' ');
  510. $.each(btnClasses, function (index, btnClass) {
  511. if ($.inArray(btnClass, buttonSizes) !== -1) {
  512. sizeClassSpecified = true;
  513. }
  514. });
  515. }
  516. if (!sizeClassSpecified) {
  517. $button.removeClass(buttonSizes.join(' '));
  518. $button.addClass(dialog.getButtonSize());
  519. }
  520. });
  521. }
  522. return this;
  523. },
  524. getCssClass: function () {
  525. return this.options.cssClass;
  526. },
  527. setCssClass: function (cssClass) {
  528. this.options.cssClass = cssClass;
  529. return this;
  530. },
  531. getTitle: function () {
  532. return this.options.title;
  533. },
  534. setTitle: function (title) {
  535. this.options.title = title;
  536. this.updateTitle();
  537. return this;
  538. },
  539. updateTitle: function () {
  540. if (this.isRealized()) {
  541. var title = this.getTitle() !== null ? this.createDynamicContent(this.getTitle()) : this.getDefaultText();
  542. this.getModalHeader().find('.' + this.getNamespace('title')).html('').append(title).prop('id', this.getId() + '_title');
  543. }
  544. return this;
  545. },
  546. getMessage: function () {
  547. return this.options.message;
  548. },
  549. setMessage: function (message) {
  550. this.options.message = message;
  551. this.updateMessage();
  552. return this;
  553. },
  554. updateMessage: function () {
  555. if (this.isRealized()) {
  556. var message = this.createDynamicContent(this.getMessage());
  557. this.getModalBody().find('.' + this.getNamespace('message')).html('').append(message);
  558. }
  559. return this;
  560. },
  561. isClosable: function () {
  562. return this.options.closable;
  563. },
  564. setClosable: function (closable) {
  565. this.options.closable = closable;
  566. this.updateClosable();
  567. return this;
  568. },
  569. setCloseByBackdrop: function (closeByBackdrop) {
  570. this.options.closeByBackdrop = closeByBackdrop;
  571. return this;
  572. },
  573. canCloseByBackdrop: function () {
  574. return this.options.closeByBackdrop;
  575. },
  576. setCloseByKeyboard: function (closeByKeyboard) {
  577. this.options.closeByKeyboard = closeByKeyboard;
  578. return this;
  579. },
  580. canCloseByKeyboard: function () {
  581. return this.options.closeByKeyboard;
  582. },
  583. isAnimate: function () {
  584. return this.options.animate;
  585. },
  586. setAnimate: function (animate) {
  587. this.options.animate = animate;
  588. return this;
  589. },
  590. updateAnimate: function () {
  591. if (this.isRealized()) {
  592. this.getModal().toggleClass('fade', this.isAnimate());
  593. }
  594. return this;
  595. },
  596. getSpinicon: function () {
  597. return this.options.spinicon;
  598. },
  599. setSpinicon: function (spinicon) {
  600. this.options.spinicon = spinicon;
  601. return this;
  602. },
  603. addButton: function (button) {
  604. this.options.buttons.push(button);
  605. return this;
  606. },
  607. addButtons: function (buttons) {
  608. var that = this;
  609. $.each(buttons, function (index, button) {
  610. that.addButton(button);
  611. });
  612. return this;
  613. },
  614. getButtons: function () {
  615. return this.options.buttons;
  616. },
  617. setButtons: function (buttons) {
  618. this.options.buttons = buttons;
  619. this.updateButtons();
  620. return this;
  621. },
  622. /**
  623. * If there is id provided for a button option, it will be in dialog.indexedButtons list.
  624. *
  625. * In that case you can use dialog.getButton(id) to find the button.
  626. *
  627. * @param {type} id
  628. * @returns {undefined}
  629. */
  630. getButton: function (id) {
  631. if (typeof this.indexedButtons[id] !== 'undefined') {
  632. return this.indexedButtons[id];
  633. }
  634. return null;
  635. },
  636. getButtonSize: function () {
  637. if (typeof BootstrapDialog.BUTTON_SIZES[this.getSize()] !== 'undefined') {
  638. return BootstrapDialog.BUTTON_SIZES[this.getSize()];
  639. }
  640. return '';
  641. },
  642. updateButtons: function () {
  643. if (this.isRealized()) {
  644. if (this.getButtons().length === 0) {
  645. this.getModalFooter().hide();
  646. } else {
  647. this.getModalFooter().show().find('.' + this.getNamespace('footer')).html('').append(this.createFooterButtons());
  648. }
  649. }
  650. return this;
  651. },
  652. isAutodestroy: function () {
  653. return this.options.autodestroy;
  654. },
  655. setAutodestroy: function (autodestroy) {
  656. this.options.autodestroy = autodestroy;
  657. },
  658. getDescription: function () {
  659. return this.options.description;
  660. },
  661. setDescription: function (description) {
  662. this.options.description = description;
  663. return this;
  664. },
  665. setTabindex: function (tabindex) {
  666. this.options.tabindex = tabindex;
  667. return this;
  668. },
  669. getTabindex: function () {
  670. return this.options.tabindex;
  671. },
  672. updateTabindex: function () {
  673. if (this.isRealized()) {
  674. this.getModal().attr('tabindex', this.getTabindex());
  675. }
  676. return this;
  677. },
  678. getDefaultText: function () {
  679. return BootstrapDialog.DEFAULT_TEXTS[this.getType()];
  680. },
  681. getNamespace: function (name) {
  682. return BootstrapDialog.NAMESPACE + '-' + name;
  683. },
  684. createHeaderContent: function () {
  685. var $container = $('<div></div>');
  686. $container.addClass(this.getNamespace('header'));
  687. // title
  688. $container.append(this.createTitleContent());
  689. // Close button
  690. $container.prepend(this.createCloseButton());
  691. return $container;
  692. },
  693. createTitleContent: function () {
  694. var $title = $('<div></div>');
  695. $title.addClass(this.getNamespace('title'));
  696. return $title;
  697. },
  698. createCloseButton: function () {
  699. var $container = $('<div></div>');
  700. $container.addClass(this.getNamespace('close-button'));
  701. var $icon = $('<button class="close"></button>');
  702. $icon.append(this.options.closeIcon);
  703. $container.append($icon);
  704. $container.on('click', {dialog: this}, function (event) {
  705. event.data.dialog.close();
  706. });
  707. return $container;
  708. },
  709. createBodyContent: function () {
  710. var $container = $('<div></div>');
  711. $container.addClass(this.getNamespace('body'));
  712. // Message
  713. $container.append(this.createMessageContent());
  714. return $container;
  715. },
  716. createMessageContent: function () {
  717. var $message = $('<div></div>');
  718. $message.addClass(this.getNamespace('message'));
  719. return $message;
  720. },
  721. createFooterContent: function () {
  722. var $container = $('<div></div>');
  723. $container.addClass(this.getNamespace('footer'));
  724. return $container;
  725. },
  726. createFooterButtons: function () {
  727. var that = this;
  728. var $container = $('<div></div>');
  729. $container.addClass(this.getNamespace('footer-buttons'));
  730. this.indexedButtons = {};
  731. $.each(this.options.buttons, function (index, button) {
  732. if (!button.id) {
  733. button.id = BootstrapDialog.newGuid();
  734. }
  735. var $button = that.createButton(button);
  736. that.indexedButtons[button.id] = $button;
  737. $container.append($button);
  738. });
  739. return $container;
  740. },
  741. createButton: function (button) {
  742. var $button = $('<button class="btn"></button>');
  743. $button.prop('id', button.id);
  744. $button.data('button', button);
  745. // Icon
  746. if (typeof button.icon !== 'undefined' && $.trim(button.icon) !== '') {
  747. $button.append(this.createButtonIcon(button.icon));
  748. }
  749. // Label
  750. if (typeof button.label !== 'undefined') {
  751. $button.append(button.label);
  752. }
  753. // Css class
  754. if (typeof button.cssClass !== 'undefined' && $.trim(button.cssClass) !== '') {
  755. $button.addClass(button.cssClass);
  756. } else {
  757. $button.addClass('btn-default');
  758. }
  759. // Hotkey
  760. if (typeof button.hotkey !== 'undefined') {
  761. this.registeredButtonHotkeys[button.hotkey] = $button;
  762. }
  763. // Button on click
  764. $button.on('click', {dialog: this, $button: $button, button: button}, function (event) {
  765. var dialog = event.data.dialog;
  766. var $button = event.data.$button;
  767. var button = $button.data('button');
  768. if (button.autospin) {
  769. $button.toggleSpin(true);
  770. }
  771. if (typeof button.action === 'function') {
  772. return button.action.call($button, dialog, event);
  773. }
  774. });
  775. // Dynamically add extra functions to $button
  776. this.enhanceButton($button);
  777. //Initialize enabled or not
  778. if (typeof button.enabled !== 'undefined') {
  779. $button.toggleEnable(button.enabled);
  780. }
  781. return $button;
  782. },
  783. /**
  784. * Dynamically add extra functions to $button
  785. *
  786. * Using '$this' to reference 'this' is just for better readability.
  787. *
  788. * @param {type} $button
  789. * @returns {_L13.BootstrapDialog.prototype}
  790. */
  791. enhanceButton: function ($button) {
  792. $button.dialog = this;
  793. // Enable / Disable
  794. $button.toggleEnable = function (enable) {
  795. var $this = this;
  796. if (typeof enable !== 'undefined') {
  797. $this.prop("disabled", !enable).toggleClass('disabled', !enable);
  798. } else {
  799. $this.prop("disabled", !$this.prop("disabled"));
  800. }
  801. return $this;
  802. };
  803. $button.enable = function () {
  804. var $this = this;
  805. $this.toggleEnable(true);
  806. return $this;
  807. };
  808. $button.disable = function () {
  809. var $this = this;
  810. $this.toggleEnable(false);
  811. return $this;
  812. };
  813. // Icon spinning, helpful for indicating ajax loading status.
  814. $button.toggleSpin = function (spin) {
  815. var $this = this;
  816. var dialog = $this.dialog;
  817. var $icon = $this.find('.' + dialog.getNamespace('button-icon'));
  818. if (typeof spin === 'undefined') {
  819. spin = !($button.find('.icon-spin').length > 0);
  820. }
  821. if (spin) {
  822. $icon.hide();
  823. $button.prepend(dialog.createButtonIcon(dialog.getSpinicon()).addClass('icon-spin'));
  824. } else {
  825. $icon.show();
  826. $button.find('.icon-spin').remove();
  827. }
  828. return $this;
  829. };
  830. $button.spin = function () {
  831. var $this = this;
  832. $this.toggleSpin(true);
  833. return $this;
  834. };
  835. $button.stopSpin = function () {
  836. var $this = this;
  837. $this.toggleSpin(false);
  838. return $this;
  839. };
  840. return this;
  841. },
  842. createButtonIcon: function (icon) {
  843. var $icon = $('<span></span>');
  844. $icon.addClass(this.getNamespace('button-icon')).addClass(icon);
  845. return $icon;
  846. },
  847. /**
  848. * Invoke this only after the dialog is realized.
  849. *
  850. * @param {type} enable
  851. * @returns {undefined}
  852. */
  853. enableButtons: function (enable) {
  854. $.each(this.indexedButtons, function (id, $button) {
  855. $button.toggleEnable(enable);
  856. });
  857. return this;
  858. },
  859. /**
  860. * Invoke this only after the dialog is realized.
  861. *
  862. * @returns {undefined}
  863. */
  864. updateClosable: function () {
  865. if (this.isRealized()) {
  866. // Close button
  867. this.getModalHeader().find('.' + this.getNamespace('close-button')).toggle(this.isClosable());
  868. }
  869. return this;
  870. },
  871. /**
  872. * Set handler for modal event 'show.bs.modal'.
  873. * This is a setter!
  874. */
  875. onShow: function (onshow) {
  876. this.options.onshow = onshow;
  877. return this;
  878. },
  879. /**
  880. * Set handler for modal event 'shown.bs.modal'.
  881. * This is a setter!
  882. */
  883. onShown: function (onshown) {
  884. this.options.onshown = onshown;
  885. return this;
  886. },
  887. /**
  888. * Set handler for modal event 'hide.bs.modal'.
  889. * This is a setter!
  890. */
  891. onHide: function (onhide) {
  892. this.options.onhide = onhide;
  893. return this;
  894. },
  895. /**
  896. * Set handler for modal event 'hidden.bs.modal'.
  897. * This is a setter!
  898. */
  899. onHidden: function (onhidden) {
  900. this.options.onhidden = onhidden;
  901. return this;
  902. },
  903. isRealized: function () {
  904. return this.realized;
  905. },
  906. setRealized: function (realized) {
  907. this.realized = realized;
  908. return this;
  909. },
  910. isOpened: function () {
  911. return this.opened;
  912. },
  913. setOpened: function (opened) {
  914. this.opened = opened;
  915. return this;
  916. },
  917. handleModalEvents: function () {
  918. this.getModal().on('show.bs.modal', {dialog: this}, function (event) {
  919. var dialog = event.data.dialog;
  920. dialog.setOpened(true);
  921. if (dialog.isModalEvent(event) && typeof dialog.options.onshow === 'function') {
  922. var openIt = dialog.options.onshow(dialog);
  923. if (openIt === false) {
  924. dialog.setOpened(false);
  925. }
  926. return openIt;
  927. }
  928. });
  929. this.getModal().on('shown.bs.modal', {dialog: this}, function (event) {
  930. var dialog = event.data.dialog;
  931. dialog.isModalEvent(event) && typeof dialog.options.onshown === 'function' && dialog.options.onshown(dialog);
  932. });
  933. this.getModal().on('hide.bs.modal', {dialog: this}, function (event) {
  934. var dialog = event.data.dialog;
  935. dialog.setOpened(false);
  936. if (dialog.isModalEvent(event) && typeof dialog.options.onhide === 'function') {
  937. var hideIt = dialog.options.onhide(dialog);
  938. if (hideIt === false) {
  939. dialog.setOpened(true);
  940. }
  941. return hideIt;
  942. }
  943. });
  944. this.getModal().on('hidden.bs.modal', {dialog: this}, function (event) {
  945. var dialog = event.data.dialog;
  946. dialog.isModalEvent(event) && typeof dialog.options.onhidden === 'function' && dialog.options.onhidden(dialog);
  947. if (dialog.isAutodestroy()) {
  948. dialog.setRealized(false);
  949. delete BootstrapDialog.dialogs[dialog.getId()];
  950. $(this).remove();
  951. }
  952. BootstrapDialog.moveFocus();
  953. });
  954. // Backdrop, I did't find a way to change bs3 backdrop option after the dialog is popped up, so here's a new wheel.
  955. this.handleModalBackdropEvent();
  956. // ESC key support
  957. this.getModal().on('keyup', {dialog: this}, function (event) {
  958. event.which === 27 && event.data.dialog.isClosable() && event.data.dialog.canCloseByKeyboard() && event.data.dialog.close();
  959. });
  960. // Button hotkey
  961. this.getModal().on('keyup', {dialog: this}, function (event) {
  962. var dialog = event.data.dialog;
  963. if (typeof dialog.registeredButtonHotkeys[event.which] !== 'undefined') {
  964. var $button = $(dialog.registeredButtonHotkeys[event.which]);
  965. !$button.prop('disabled') && $button.focus().trigger('click');
  966. }
  967. });
  968. return this;
  969. },
  970. handleModalBackdropEvent: function () {
  971. this.getModal().on('click', {dialog: this}, function (event) {
  972. $(event.target).hasClass('modal-backdrop') && event.data.dialog.isClosable() && event.data.dialog.canCloseByBackdrop() && event.data.dialog.close();
  973. });
  974. return this;
  975. },
  976. isModalEvent: function (event) {
  977. return typeof event.namespace !== 'undefined' && event.namespace === 'bs.modal';
  978. },
  979. makeModalDraggable: function () {
  980. if (this.options.draggable) {
  981. this.getModalHeader().addClass(this.getNamespace('draggable')).on('mousedown', {dialog: this}, function (event) {
  982. var dialog = event.data.dialog;
  983. dialog.draggableData.isMouseDown = true;
  984. var dialogOffset = dialog.getModalDialog().offset();
  985. dialog.draggableData.mouseOffset = {
  986. top: event.clientY - dialogOffset.top,
  987. left: event.clientX - dialogOffset.left
  988. };
  989. });
  990. this.getModal().on('mouseup mouseleave', {dialog: this}, function (event) {
  991. event.data.dialog.draggableData.isMouseDown = false;
  992. });
  993. $('body').on('mousemove', {dialog: this}, function (event) {
  994. var dialog = event.data.dialog;
  995. if (!dialog.draggableData.isMouseDown) {
  996. return;
  997. }
  998. dialog.getModalDialog().offset({
  999. top: event.clientY - dialog.draggableData.mouseOffset.top,
  1000. left: event.clientX - dialog.draggableData.mouseOffset.left
  1001. });
  1002. });
  1003. }
  1004. return this;
  1005. },
  1006. realize: function () {
  1007. this.initModalStuff();
  1008. this.getModal().addClass(BootstrapDialog.NAMESPACE)
  1009. .addClass(this.getCssClass());
  1010. this.updateSize();
  1011. if (this.getDescription()) {
  1012. this.getModal().attr('aria-describedby', this.getDescription());
  1013. }
  1014. this.getModalFooter().append(this.createFooterContent());
  1015. this.getModalHeader().append(this.createHeaderContent());
  1016. this.getModalBody().append(this.createBodyContent());
  1017. this.getModal().data('bs.modal', new BootstrapDialogModal(this.getModal(), {
  1018. backdrop: 'static',
  1019. keyboard: false,
  1020. show: false
  1021. }));
  1022. this.makeModalDraggable();
  1023. this.handleModalEvents();
  1024. this.setRealized(true);
  1025. this.updateButtons();
  1026. this.updateType();
  1027. this.updateTitle();
  1028. this.updateMessage();
  1029. this.updateClosable();
  1030. this.updateAnimate();
  1031. this.updateSize();
  1032. this.updateTabindex();
  1033. return this;
  1034. },
  1035. open: function () {
  1036. !this.isRealized() && this.realize();
  1037. this.getModal().modal('show');
  1038. return this;
  1039. },
  1040. close: function () {
  1041. !this.isRealized() && this.realize();
  1042. this.getModal().modal('hide');
  1043. return this;
  1044. }
  1045. };
  1046. // Add compatible methods.
  1047. BootstrapDialog.prototype = $.extend(BootstrapDialog.prototype, BootstrapDialog.METHODS_TO_OVERRIDE[BootstrapDialogModal.getModalVersion()]);
  1048. /**
  1049. * RFC4122 version 4 compliant unique id creator.
  1050. *
  1051. * Added by https://github.com/tufanbarisyildirim/
  1052. *
  1053. * @returns {String}
  1054. */
  1055. BootstrapDialog.newGuid = function () {
  1056. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
  1057. var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
  1058. return v.toString(16);
  1059. });
  1060. };
  1061. /* ================================================
  1062. * For lazy people
  1063. * ================================================ */
  1064. /**
  1065. * Shortcut function: show
  1066. *
  1067. * @param {type} options
  1068. * @returns the created dialog instance
  1069. */
  1070. BootstrapDialog.show = function (options) {
  1071. return new BootstrapDialog(options).open();
  1072. };
  1073. /**
  1074. * Alert window
  1075. *
  1076. * @returns the created dialog instance
  1077. */
  1078. BootstrapDialog.alert = function () {
  1079. var alertOptions = {};
  1080. var defaultAlertOptions = {
  1081. type: BootstrapDialog.TYPE_PRIMARY,
  1082. title: null,
  1083. message: null,
  1084. closable: false,
  1085. draggable: false,
  1086. buttonLabel: BootstrapDialog.DEFAULT_TEXTS.OK,
  1087. callback: null
  1088. };
  1089. if (typeof arguments[0] === 'object' && arguments[0].constructor === {}.constructor) {
  1090. alertOptions = $.extend(true, defaultAlertOptions, arguments[0]);
  1091. } else {
  1092. alertOptions = $.extend(true, defaultAlertOptions, {
  1093. message: arguments[0],
  1094. callback: typeof arguments[1] !== 'undefined' ? arguments[1] : null
  1095. });
  1096. }
  1097. var dialog = new BootstrapDialog(alertOptions);
  1098. dialog.setData('callback', alertOptions.callback);
  1099. dialog.addButton({
  1100. label: alertOptions.buttonLabel,
  1101. action: function (dialog) {
  1102. if (typeof dialog.getData('callback') === 'function' && dialog.getData('callback').call(this, true) === false) {
  1103. return false;
  1104. }
  1105. dialog.setData('btnClicked', true);
  1106. return dialog.close();
  1107. }
  1108. });
  1109. if (typeof dialog.options.onhide === 'function') {
  1110. dialog.onHide(function (dialog) {
  1111. var hideIt = true;
  1112. if (!dialog.getData('btnClicked') && dialog.isClosable() && typeof dialog.getData('callback') === 'function') {
  1113. hideIt = dialog.getData('callback')(false);
  1114. }
  1115. if (hideIt === false) {
  1116. return false;
  1117. }
  1118. hideIt = this.onhide(dialog);
  1119. return hideIt;
  1120. }.bind({
  1121. onhide: dialog.options.onhide
  1122. }));
  1123. } else {
  1124. dialog.onHide(function (dialog) {
  1125. var hideIt = true;
  1126. if (!dialog.getData('btnClicked') && dialog.isClosable() && typeof dialog.getData('callback') === 'function') {
  1127. hideIt = dialog.getData('callback')(false);
  1128. }
  1129. return hideIt;
  1130. });
  1131. }
  1132. return dialog.open();
  1133. };
  1134. /**
  1135. * Confirm window
  1136. *
  1137. * @returns the created dialog instance
  1138. */
  1139. BootstrapDialog.confirm = function () {
  1140. var confirmOptions = {};
  1141. var defaultConfirmOptions = {
  1142. type: BootstrapDialog.TYPE_PRIMARY,
  1143. title: null,
  1144. message: null,
  1145. closable: false,
  1146. draggable: false,
  1147. btnCancelLabel: BootstrapDialog.DEFAULT_TEXTS.CANCEL,
  1148. btnCancelClass: null,
  1149. btnOKLabel: BootstrapDialog.DEFAULT_TEXTS.OK,
  1150. btnOKClass: null,
  1151. callback: null
  1152. };
  1153. if (typeof arguments[0] === 'object' && arguments[0].constructor === {}.constructor) {
  1154. confirmOptions = $.extend(true, defaultConfirmOptions, arguments[0]);
  1155. } else {
  1156. confirmOptions = $.extend(true, defaultConfirmOptions, {
  1157. message: arguments[0],
  1158. callback: typeof arguments[1] !== 'undefined' ? arguments[1] : null
  1159. });
  1160. }
  1161. if (confirmOptions.btnOKClass === null) {
  1162. confirmOptions.btnOKClass = ['btn', confirmOptions.type.split('-')[1]].join('-');
  1163. }
  1164. var dialog = new BootstrapDialog(confirmOptions);
  1165. dialog.setData('callback', confirmOptions.callback);
  1166. dialog.addButton({
  1167. label: confirmOptions.btnCancelLabel,
  1168. cssClass: confirmOptions.btnCancelClass,
  1169. action: function (dialog) {
  1170. if (typeof dialog.getData('callback') === 'function' && dialog.getData('callback').call(this, false) === false) {
  1171. return false;
  1172. }
  1173. return dialog.close();
  1174. }
  1175. });
  1176. dialog.addButton({
  1177. label: confirmOptions.btnOKLabel,
  1178. cssClass: confirmOptions.btnOKClass,
  1179. action: function (dialog) {
  1180. if (typeof dialog.getData('callback') === 'function' && dialog.getData('callback').call(this, true) === false) {
  1181. return false;
  1182. }
  1183. return dialog.close();
  1184. }
  1185. });
  1186. return dialog.open();
  1187. };
  1188. /**
  1189. * Warning window
  1190. *
  1191. * @param {type} message
  1192. * @returns the created dialog instance
  1193. */
  1194. BootstrapDialog.warning = function (message, callback) {
  1195. return new BootstrapDialog({
  1196. type: BootstrapDialog.TYPE_WARNING,
  1197. message: message
  1198. }).open();
  1199. };
  1200. /**
  1201. * Danger window
  1202. *
  1203. * @param {type} message
  1204. * @returns the created dialog instance
  1205. */
  1206. BootstrapDialog.danger = function (message, callback) {
  1207. return new BootstrapDialog({
  1208. type: BootstrapDialog.TYPE_DANGER,
  1209. message: message
  1210. }).open();
  1211. };
  1212. /**
  1213. * Success window
  1214. *
  1215. * @param {type} message
  1216. * @returns the created dialog instance
  1217. */
  1218. BootstrapDialog.success = function (message, callback) {
  1219. return new BootstrapDialog({
  1220. type: BootstrapDialog.TYPE_SUCCESS,
  1221. message: message
  1222. }).open();
  1223. };
  1224. return BootstrapDialog;
  1225. }));