bootstrap-dialog.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  1. /* ================================================
  2. * Make use of Bootstrap's modal more monkey-friendly.
  3. *
  4. * For Bootstrap 3.
  5. *
  6. * javanoob@hotmail.com
  7. *
  8. * https://github.com/nakupanda/bootstrap3-dialog
  9. *
  10. * Licensed under The MIT License.
  11. * ================================================ */
  12. (function($) {
  13. "use strict";
  14. var BootstrapDialog = function(options) {
  15. this.defaultOptions = $.extend(true, {
  16. id: BootstrapDialog.newGuid(),
  17. buttons: [],
  18. data: {},
  19. onshow: null,
  20. onshown: null,
  21. onhide: null,
  22. onhidden: null
  23. }, BootstrapDialog.defaultOptions);
  24. this.indexedButtons = {};
  25. this.registeredButtonHotkeys = {};
  26. this.draggableData = {
  27. isMouseDown: false,
  28. mouseOffset: {}
  29. };
  30. this.realized = false;
  31. this.opened = false;
  32. this.initOptions(options);
  33. this.holdThisInstance();
  34. };
  35. /**
  36. * Some constants.
  37. */
  38. BootstrapDialog.NAMESPACE = 'bootstrap-dialog';
  39. BootstrapDialog.TYPE_DEFAULT = 'type-default';
  40. BootstrapDialog.TYPE_INFO = 'type-info';
  41. BootstrapDialog.TYPE_PRIMARY = 'type-primary';
  42. BootstrapDialog.TYPE_SUCCESS = 'type-success';
  43. BootstrapDialog.TYPE_WARNING = 'type-warning';
  44. BootstrapDialog.TYPE_DANGER = 'type-danger';
  45. BootstrapDialog.DEFAULT_TEXTS = {};
  46. BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_DEFAULT] = 'Information';
  47. BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_INFO] = 'Information';
  48. BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_PRIMARY] = 'Information';
  49. BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_SUCCESS] = 'Success';
  50. BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_WARNING] = 'Warning';
  51. BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_DANGER] = 'Danger';
  52. BootstrapDialog.SIZE_NORMAL = 'size-normal';
  53. BootstrapDialog.SIZE_LARGE = 'size-large';
  54. BootstrapDialog.BUTTON_SIZES = {};
  55. BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_NORMAL] = '';
  56. BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_LARGE] = 'btn-lg';
  57. BootstrapDialog.ICON_SPINNER = 'glyphicon glyphicon-asterisk';
  58. BootstrapDialog.ZINDEX_BACKDROP = 1040;
  59. BootstrapDialog.ZINDEX_MODAL = 1050;
  60. /**
  61. * Default options.
  62. */
  63. BootstrapDialog.defaultOptions = {
  64. type: BootstrapDialog.TYPE_PRIMARY,
  65. size: BootstrapDialog.SIZE_NORMAL,
  66. cssClass: '',
  67. title: null,
  68. message: null,
  69. nl2br: true,
  70. closable: true,
  71. closeByBackdrop: true,
  72. closeByKeyboard: true,
  73. spinicon: BootstrapDialog.ICON_SPINNER,
  74. autodestroy: true,
  75. draggable: false
  76. };
  77. /**
  78. * Config default options.
  79. */
  80. BootstrapDialog.configDefaultOptions = function(options) {
  81. BootstrapDialog.defaultOptions = $.extend(true, BootstrapDialog.defaultOptions, options);
  82. };
  83. /**
  84. * Open / Close all created dialogs all at once.
  85. */
  86. BootstrapDialog.dialogs = {};
  87. BootstrapDialog.openAll = function() {
  88. $.each(BootstrapDialog.dialogs, function(id, dialogInstance) {
  89. dialogInstance.open();
  90. });
  91. };
  92. BootstrapDialog.closeAll = function() {
  93. $.each(BootstrapDialog.dialogs, function(id, dialogInstance) {
  94. dialogInstance.close();
  95. });
  96. };
  97. BootstrapDialog.prototype = {
  98. constructor: BootstrapDialog,
  99. initOptions: function(options) {
  100. this.options = $.extend(true, this.defaultOptions, options);
  101. return this;
  102. },
  103. holdThisInstance: function() {
  104. BootstrapDialog.dialogs[this.getId()] = this;
  105. return this;
  106. },
  107. initModalStuff: function() {
  108. this.setModal(this.createModal())
  109. .setModalDialog(this.createModalDialog())
  110. .setModalContent(this.createModalContent())
  111. .setModalHeader(this.createModalHeader())
  112. .setModalBody(this.createModalBody())
  113. .setModalFooter(this.createModalFooter());
  114. this.getModal().append(this.getModalDialog());
  115. this.getModalDialog().append(this.getModalContent());
  116. this.getModalContent()
  117. .append(this.getModalHeader())
  118. .append(this.getModalBody())
  119. .append(this.getModalFooter());
  120. return this;
  121. },
  122. createModal: function() {
  123. var $modal = $('<div class="modal fade" tabindex="-1"></div>');
  124. $modal.prop('id', this.getId());
  125. return $modal;
  126. },
  127. getModal: function() {
  128. return this.$modal;
  129. },
  130. setModal: function($modal) {
  131. this.$modal = $modal;
  132. return this;
  133. },
  134. createModalDialog: function() {
  135. return $('<div class="modal-dialog"></div>');
  136. },
  137. getModalDialog: function() {
  138. return this.$modalDialog;
  139. },
  140. setModalDialog: function($modalDialog) {
  141. this.$modalDialog = $modalDialog;
  142. return this;
  143. },
  144. createModalContent: function() {
  145. return $('<div class="modal-content"></div>');
  146. },
  147. getModalContent: function() {
  148. return this.$modalContent;
  149. },
  150. setModalContent: function($modalContent) {
  151. this.$modalContent = $modalContent;
  152. return this;
  153. },
  154. createModalHeader: function() {
  155. return $('<div class="modal-header"></div>');
  156. },
  157. getModalHeader: function() {
  158. return this.$modalHeader;
  159. },
  160. setModalHeader: function($modalHeader) {
  161. this.$modalHeader = $modalHeader;
  162. return this;
  163. },
  164. createModalBody: function() {
  165. return $('<div class="modal-body"></div>');
  166. },
  167. getModalBody: function() {
  168. return this.$modalBody;
  169. },
  170. setModalBody: function($modalBody) {
  171. this.$modalBody = $modalBody;
  172. return this;
  173. },
  174. createModalFooter: function() {
  175. return $('<div class="modal-footer"></div>');
  176. },
  177. getModalFooter: function() {
  178. return this.$modalFooter;
  179. },
  180. setModalFooter: function($modalFooter) {
  181. this.$modalFooter = $modalFooter;
  182. return this;
  183. },
  184. createDynamicContent: function(rawContent) {
  185. var content = null;
  186. if (typeof rawContent === 'function') {
  187. content = rawContent.call(rawContent, this);
  188. } else {
  189. content = rawContent;
  190. }
  191. if (typeof content === 'string') {
  192. content = this.formatStringContent(content);
  193. }
  194. return content;
  195. },
  196. formatStringContent: function(content) {
  197. if (this.options.nl2br) {
  198. return content.replace(/\r\n/g, '<br />').replace(/[\r\n]/g, '<br />');
  199. }
  200. return content;
  201. },
  202. setData: function(key, value) {
  203. this.options.data[key] = value;
  204. return this;
  205. },
  206. getData: function(key) {
  207. return this.options.data[key];
  208. },
  209. setId: function(id) {
  210. this.options.id = id;
  211. return this;
  212. },
  213. getId: function() {
  214. return this.options.id;
  215. },
  216. getType: function() {
  217. return this.options.type;
  218. },
  219. setType: function(type) {
  220. this.options.type = type;
  221. return this;
  222. },
  223. getSize: function() {
  224. return this.options.size;
  225. },
  226. setSize: function(size) {
  227. this.options.size = size;
  228. return this;
  229. },
  230. getCssClass: function() {
  231. return this.options.cssClass;
  232. },
  233. setCssClass: function(cssClass) {
  234. this.options.cssClass = cssClass;
  235. return this;
  236. },
  237. getTitle: function() {
  238. return this.options.title;
  239. },
  240. setTitle: function(title) {
  241. this.options.title = title;
  242. this.updateTitle();
  243. return this;
  244. },
  245. updateTitle: function() {
  246. if (this.isRealized()) {
  247. var title = this.getTitle() !== null ? this.createDynamicContent(this.getTitle()) : this.getDefaultText();
  248. this.getModalHeader().find('.' + this.getNamespace('title')).html('').append(title);
  249. }
  250. return this;
  251. },
  252. getMessage: function() {
  253. return this.options.message;
  254. },
  255. setMessage: function(message) {
  256. this.options.message = message;
  257. this.updateMessage();
  258. return this;
  259. },
  260. updateMessage: function() {
  261. if (this.isRealized()) {
  262. var message = this.createDynamicContent(this.getMessage());
  263. this.getModalBody().find('.' + this.getNamespace('message')).html('').append(message);
  264. }
  265. return this;
  266. },
  267. isClosable: function() {
  268. return this.options.closable;
  269. },
  270. setClosable: function(closable) {
  271. this.options.closable = closable;
  272. this.updateClosable();
  273. return this;
  274. },
  275. setCloseByBackdrop: function(closeByBackdrop) {
  276. this.options.closeByBackdrop = closeByBackdrop;
  277. return this;
  278. },
  279. canCloseByBackdrop: function() {
  280. return this.options.closeByBackdrop;
  281. },
  282. setCloseByKeyboard: function(closeByKeyboard) {
  283. this.options.closeByKeyboard = closeByKeyboard;
  284. return this;
  285. },
  286. canCloseByKeyboard: function() {
  287. return this.options.closeByKeyboard;
  288. },
  289. getSpinicon: function() {
  290. return this.options.spinicon;
  291. },
  292. setSpinicon: function(spinicon) {
  293. this.options.spinicon = spinicon;
  294. return this;
  295. },
  296. addButton: function(button) {
  297. this.options.buttons.push(button);
  298. return this;
  299. },
  300. addButtons: function(buttons) {
  301. var that = this;
  302. $.each(buttons, function(index, button) {
  303. that.addButton(button);
  304. });
  305. return this;
  306. },
  307. getButtons: function() {
  308. return this.options.buttons;
  309. },
  310. setButtons: function(buttons) {
  311. this.options.buttons = buttons;
  312. this.updateButtons();
  313. return this;
  314. },
  315. /**
  316. * If there is id provided for a button option, it will be in dialog.indexedButtons list.
  317. *
  318. * In that case you can use dialog.getButton(id) to find the button.
  319. *
  320. * @param {type} id
  321. * @returns {undefined}
  322. */
  323. getButton: function(id) {
  324. if (typeof this.indexedButtons[id] !== 'undefined') {
  325. return this.indexedButtons[id];
  326. }
  327. return null;
  328. },
  329. getButtonSize: function() {
  330. if (typeof BootstrapDialog.BUTTON_SIZES[this.getSize()] !== 'undefined') {
  331. return BootstrapDialog.BUTTON_SIZES[this.getSize()];
  332. }
  333. return '';
  334. },
  335. updateButtons: function() {
  336. if (this.isRealized()) {
  337. if (this.getButtons().length === 0) {
  338. this.getModalFooter().hide();
  339. } else {
  340. this.getModalFooter().find('.' + this.getNamespace('footer')).html('').append(this.createFooterButtons());
  341. }
  342. }
  343. return this;
  344. },
  345. isAutodestroy: function() {
  346. return this.options.autodestroy;
  347. },
  348. setAutodestroy: function(autodestroy) {
  349. this.options.autodestroy = autodestroy;
  350. },
  351. getDefaultText: function() {
  352. return BootstrapDialog.DEFAULT_TEXTS[this.getType()];
  353. },
  354. getNamespace: function(name) {
  355. return BootstrapDialog.NAMESPACE + '-' + name;
  356. },
  357. createHeaderContent: function() {
  358. var $container = $('<div></div>');
  359. $container.addClass(this.getNamespace('header'));
  360. // title
  361. $container.append(this.createTitleContent());
  362. // Close button
  363. $container.prepend(this.createCloseButton());
  364. return $container;
  365. },
  366. createTitleContent: function() {
  367. var $title = $('<div></div>');
  368. $title.addClass(this.getNamespace('title'));
  369. return $title;
  370. },
  371. createCloseButton: function() {
  372. var $container = $('<div></div>');
  373. $container.addClass(this.getNamespace('close-button'));
  374. var $icon = $('<button class="close">&times;</button>');
  375. $container.append($icon);
  376. $container.on('click', {dialog: this}, function(event) {
  377. event.data.dialog.close();
  378. });
  379. return $container;
  380. },
  381. createBodyContent: function() {
  382. var $container = $('<div></div>');
  383. $container.addClass(this.getNamespace('body'));
  384. // Message
  385. $container.append(this.createMessageContent());
  386. return $container;
  387. },
  388. createMessageContent: function() {
  389. var $message = $('<div></div>');
  390. $message.addClass(this.getNamespace('message'));
  391. return $message;
  392. },
  393. createFooterContent: function() {
  394. var $container = $('<div></div>');
  395. $container.addClass(this.getNamespace('footer'));
  396. return $container;
  397. },
  398. createFooterButtons: function() {
  399. var that = this;
  400. var $container = $('<div></div>');
  401. $container.addClass(this.getNamespace('footer-buttons'));
  402. this.indexedButtons = {};
  403. $.each(this.options.buttons, function(index, button) {
  404. if (!button.id) {
  405. button.id = BootstrapDialog.newGuid();
  406. }
  407. var $button = that.createButton(button);
  408. that.indexedButtons[button.id] = $button;
  409. $container.append($button);
  410. });
  411. return $container;
  412. },
  413. createButton: function(button) {
  414. var $button = $('<button class="btn"></button>');
  415. $button.addClass(this.getButtonSize());
  416. $button.prop('id', button.id);
  417. // Icon
  418. if (typeof button.icon !== 'undefined' && $.trim(button.icon) !== '') {
  419. $button.append(this.createButtonIcon(button.icon));
  420. }
  421. // Label
  422. if (typeof button.label !== 'undefined') {
  423. $button.append(button.label);
  424. }
  425. // Css class
  426. if (typeof button.cssClass !== 'undefined' && $.trim(button.cssClass) !== '') {
  427. $button.addClass(button.cssClass);
  428. } else {
  429. $button.addClass('btn-default');
  430. }
  431. // Hotkey
  432. if (typeof button.hotkey !== 'undefined') {
  433. this.registeredButtonHotkeys[button.hotkey] = $button;
  434. }
  435. // Button on click
  436. $button.on('click', {dialog: this, $button: $button, button: button}, function(event) {
  437. var dialog = event.data.dialog;
  438. var $button = event.data.$button;
  439. var button = event.data.button;
  440. if (typeof button.action === 'function') {
  441. button.action.call($button, dialog);
  442. }
  443. if (button.autospin) {
  444. $button.toggleSpin(true);
  445. }
  446. });
  447. // Dynamically add extra functions to $button
  448. this.enhanceButton($button);
  449. return $button;
  450. },
  451. /**
  452. * Dynamically add extra functions to $button
  453. *
  454. * Using '$this' to reference 'this' is just for better readability.
  455. *
  456. * @param {type} $button
  457. * @returns {_L13.BootstrapDialog.prototype}
  458. */
  459. enhanceButton: function($button) {
  460. $button.dialog = this;
  461. // Enable / Disable
  462. $button.toggleEnable = function(enable) {
  463. var $this = this;
  464. $this.prop("disabled", !enable).toggleClass('disabled', !enable);
  465. return $this;
  466. };
  467. $button.enable = function() {
  468. var $this = this;
  469. $this.toggleEnable(true);
  470. return $this;
  471. };
  472. $button.disable = function() {
  473. var $this = this;
  474. $this.toggleEnable(false);
  475. return $this;
  476. };
  477. // Icon spinning, helpful for indicating ajax loading status.
  478. $button.toggleSpin = function(spin) {
  479. var $this = this;
  480. var dialog = $this.dialog;
  481. var $icon = $this.find('.' + dialog.getNamespace('button-icon'));
  482. if (spin) {
  483. $icon.hide();
  484. $button.prepend(dialog.createButtonIcon(dialog.getSpinicon()).addClass('icon-spin'));
  485. } else {
  486. $icon.show();
  487. $button.find('.icon-spin').remove();
  488. }
  489. return $this;
  490. };
  491. $button.spin = function() {
  492. var $this = this;
  493. $this.toggleSpin(true);
  494. return $this;
  495. };
  496. $button.stopSpin = function() {
  497. var $this = this;
  498. $this.toggleSpin(false);
  499. return $this;
  500. };
  501. return this;
  502. },
  503. createButtonIcon: function(icon) {
  504. var $icon = $('<span></span>');
  505. $icon.addClass(this.getNamespace('button-icon')).addClass(icon);
  506. return $icon;
  507. },
  508. /**
  509. * Invoke this only after the dialog is realized.
  510. *
  511. * @param {type} enable
  512. * @returns {undefined}
  513. */
  514. enableButtons: function(enable) {
  515. $.each(this.indexedButtons, function(id, $button) {
  516. $button.toggleEnable(enable);
  517. });
  518. return this;
  519. },
  520. /**
  521. * Invoke this only after the dialog is realized.
  522. *
  523. * @returns {undefined}
  524. */
  525. updateClosable: function() {
  526. if (this.isRealized()) {
  527. // Close button
  528. this.getModalHeader().find('.' + this.getNamespace('close-button')).toggle(this.isClosable());
  529. }
  530. return this;
  531. },
  532. /**
  533. * Set handler for modal event 'show.bs.modal'.
  534. * This is a setter!
  535. */
  536. onShow: function(onshow) {
  537. this.options.onshow = onshow;
  538. return this;
  539. },
  540. /**
  541. * Set handler for modal event 'shown.bs.modal'.
  542. * This is a setter!
  543. */
  544. onShown: function(onshown) {
  545. this.options.onshown = onshown;
  546. return this;
  547. },
  548. /**
  549. * Set handler for modal event 'hide.bs.modal'.
  550. * This is a setter!
  551. */
  552. onHide: function(onhide) {
  553. this.options.onhide = onhide;
  554. return this;
  555. },
  556. /**
  557. * Set handler for modal event 'hidden.bs.modal'.
  558. * This is a setter!
  559. */
  560. onHidden: function(onhidden) {
  561. this.options.onhidden = onhidden;
  562. return this;
  563. },
  564. isRealized: function() {
  565. return this.realized;
  566. },
  567. setRealized: function(realized) {
  568. this.realized = realized;
  569. return this;
  570. },
  571. isOpened: function() {
  572. return this.opened;
  573. },
  574. setOpened: function(opened) {
  575. this.opened = opened;
  576. return this;
  577. },
  578. handleModalEvents: function() {
  579. this.getModal().on('show.bs.modal', {dialog: this}, function(event) {
  580. var dialog = event.data.dialog;
  581. dialog.showPageScrollBar(true);
  582. if (typeof dialog.options.onshow === 'function') {
  583. return dialog.options.onshow(dialog);
  584. }
  585. });
  586. this.getModal().on('shown.bs.modal', {dialog: this}, function(event) {
  587. var dialog = event.data.dialog;
  588. typeof dialog.options.onshown === 'function' && dialog.options.onshown(dialog);
  589. dialog.showPageScrollBar(true);
  590. });
  591. this.getModal().on('hide.bs.modal', {dialog: this}, function(event) {
  592. var dialog = event.data.dialog;
  593. if (typeof dialog.options.onhide === 'function') {
  594. return dialog.options.onhide(dialog);
  595. }
  596. });
  597. this.getModal().on('hidden.bs.modal', {dialog: this}, function(event) {
  598. var dialog = event.data.dialog;
  599. typeof dialog.options.onhidden === 'function' && dialog.options.onhidden(dialog);
  600. dialog.isAutodestroy() && $(this).remove();
  601. dialog.showPageScrollBar(false);
  602. });
  603. // Backdrop, I did't find a way to change bs3 backdrop option after the dialog is popped up, so here's a new wheel.
  604. this.getModal().on('click', {dialog: this}, function(event) {
  605. event.target === this && event.data.dialog.isClosable() && event.data.dialog.canCloseByBackdrop() && event.data.dialog.close();
  606. });
  607. // ESC key support
  608. this.getModal().on('keyup', {dialog: this}, function(event) {
  609. event.which === 27 && event.data.dialog.isClosable() && event.data.dialog.canCloseByKeyboard() && event.data.dialog.close();
  610. });
  611. // Button hotkey
  612. this.getModal().on('keyup', {dialog: this}, function(event) {
  613. var dialog = event.data.dialog;
  614. if (typeof dialog.registeredButtonHotkeys[event.which] !== 'undefined') {
  615. var $button = $(dialog.registeredButtonHotkeys[event.which]);
  616. !$button.prop('disabled') && $button.focus().trigger('click');
  617. }
  618. });
  619. return this;
  620. },
  621. makeModalDraggable: function() {
  622. if (this.options.draggable) {
  623. this.getModalHeader().addClass(this.getNamespace('draggable')).on('mousedown', {dialog: this}, function(event) {
  624. var dialog = event.data.dialog;
  625. dialog.draggableData.isMouseDown = true;
  626. var dialogOffset = dialog.getModalContent().offset();
  627. dialog.draggableData.mouseOffset = {
  628. top: event.clientY - dialogOffset.top,
  629. left: event.clientX - dialogOffset.left
  630. };
  631. });
  632. this.getModal().on('mouseup mouseleave', {dialog: this}, function(event) {
  633. event.data.dialog.draggableData.isMouseDown = false;
  634. });
  635. $('body').on('mousemove', {dialog: this}, function(event) {
  636. var dialog = event.data.dialog;
  637. if (!dialog.draggableData.isMouseDown) {
  638. return;
  639. }
  640. dialog.getModalContent().offset({
  641. top: event.clientY - dialog.draggableData.mouseOffset.top,
  642. left: event.clientX - dialog.draggableData.mouseOffset.left
  643. });
  644. });
  645. }
  646. return this;
  647. },
  648. showPageScrollBar: function(show) {
  649. $(document.body).toggleClass('modal-open', show);
  650. },
  651. /**
  652. * To make multiple opened dialogs look better.
  653. */
  654. updateZIndex: function() {
  655. var dialogCount = Object.keys(BootstrapDialog.dialogs).length;
  656. if (dialogCount > 1) {
  657. var $modal = this.getModal();
  658. var $backdrop = $modal.data('bs.modal').$backdrop;
  659. $modal.css('z-index', BootstrapDialog.ZINDEX_MODAL + (dialogCount - 1) * 20);
  660. $backdrop.css('z-index', BootstrapDialog.ZINDEX_BACKDROP + (dialogCount - 1) * 20);
  661. }
  662. return this;
  663. },
  664. realize: function() {
  665. this.initModalStuff();
  666. this.getModal().addClass(BootstrapDialog.NAMESPACE)
  667. .addClass(this.getType())
  668. .addClass(this.getSize())
  669. .addClass(this.getCssClass());
  670. this.getModalFooter().append(this.createFooterContent());
  671. this.getModalHeader().append(this.createHeaderContent());
  672. this.getModalBody().append(this.createBodyContent());
  673. this.getModal().modal({
  674. backdrop: 'static',
  675. keyboard: false,
  676. show: false
  677. });
  678. this.makeModalDraggable();
  679. this.handleModalEvents();
  680. this.setRealized(true);
  681. this.updateButtons();
  682. this.updateTitle();
  683. this.updateMessage();
  684. this.updateClosable();
  685. return this;
  686. },
  687. open: function() {
  688. !this.isRealized() && this.realize();
  689. this.getModal().modal('show');
  690. this.updateZIndex();
  691. this.setOpened(true);
  692. return this;
  693. },
  694. close: function() {
  695. this.getModal().modal('hide');
  696. if (this.isAutodestroy()) {
  697. delete BootstrapDialog.dialogs[this.getId()];
  698. }
  699. this.setOpened(false);
  700. return this;
  701. }
  702. };
  703. /**
  704. * RFC4122 version 4 compliant unique id creator.
  705. *
  706. * Added by https://github.com/tufanbarisyildirim/
  707. *
  708. * @returns {String}
  709. */
  710. BootstrapDialog.newGuid = function() {
  711. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
  712. var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
  713. return v.toString(16);
  714. });
  715. };
  716. /* ================================================
  717. * For lazy people
  718. * ================================================ */
  719. /**
  720. * Shortcut function: show
  721. *
  722. * @param {type} options
  723. * @returns the created dialog instance
  724. */
  725. BootstrapDialog.show = function(options) {
  726. return new BootstrapDialog(options).open();
  727. };
  728. /**
  729. * Alert window
  730. *
  731. * @returns the created dialog instance
  732. */
  733. BootstrapDialog.alert = function() {
  734. var options = {};
  735. var defaultOptions = {
  736. type: BootstrapDialog.TYPE_PRIMARY,
  737. title: null,
  738. message: null,
  739. closable: true,
  740. buttonLabel: 'OK',
  741. callback: null
  742. };
  743. if (typeof arguments[0] === 'object' && arguments[0].constructor === {}.constructor) {
  744. options = $.extend(true, defaultOptions, arguments[0]);
  745. } else {
  746. options = $.extend(true, defaultOptions, {
  747. message: arguments[0],
  748. closable: false,
  749. buttonLabel: 'OK',
  750. callback: typeof arguments[1] !== 'undefined' ? arguments[1] : null
  751. });
  752. }
  753. return new BootstrapDialog({
  754. type: options.type,
  755. title: options.title,
  756. message: options.message,
  757. closable: options.closable,
  758. data: {
  759. callback: options.callback
  760. },
  761. onhide: function(dialog) {
  762. !dialog.getData('btnClicked') && dialog.isClosable() && typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(false);
  763. },
  764. buttons: [{
  765. label: options.buttonLabel,
  766. action: function(dialog) {
  767. dialog.setData('btnClicked', true);
  768. typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(true);
  769. dialog.close();
  770. }
  771. }]
  772. }).open();
  773. };
  774. /**
  775. * Confirm window
  776. *
  777. * @param {type} message
  778. * @param {type} callback
  779. * @returns the created dialog instance
  780. */
  781. BootstrapDialog.confirm = function(message, callback) {
  782. return new BootstrapDialog({
  783. title: 'Confirmation',
  784. message: message,
  785. closable: false,
  786. data: {
  787. 'callback': callback
  788. },
  789. buttons: [{
  790. label: 'Cancel',
  791. action: function(dialog) {
  792. typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(false);
  793. dialog.close();
  794. }
  795. }, {
  796. label: 'OK',
  797. cssClass: 'btn-primary',
  798. action: function(dialog) {
  799. typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(true);
  800. dialog.close();
  801. }
  802. }]
  803. }).open();
  804. };
  805. BootstrapDialog.init = function() {
  806. // check for nodeJS
  807. var hasModule = (typeof module !== 'undefined' && module.exports);
  808. // CommonJS module is defined
  809. if (hasModule)
  810. module.exports = BootstrapDialog;
  811. else if (typeof define === "function" && define.amd)
  812. define("bootstrap-dialog", function() {
  813. return BootstrapDialog;
  814. });
  815. else
  816. window.BootstrapDialog = BootstrapDialog;
  817. };
  818. BootstrapDialog.init();
  819. })(window.jQuery);