bootstrap-dialog.js 33 KB

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