bootstrap-confirmation.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*!
  2. * Bootstrap Confirmation
  3. * Copyright 2013 Nimit Suwannagate <ethaizone@hotmail.com>
  4. * Copyright 2014 Damien "Mistic" Sorel <http://www.strangeplanet.fr>
  5. * Licensed under the Apache License, Version 2.0 (the "License")
  6. */
  7. (function ($) {
  8. 'use strict';
  9. // Confirmation extends popover.js
  10. if (!$.fn.popover) throw new Error('Confirmation requires popover.js');
  11. // CONFIRMATION PUBLIC CLASS DEFINITION
  12. // ===============================
  13. var Confirmation = function (element, options) {
  14. this.init('confirmation', element, options);
  15. var that = this;
  16. if (!this.options.selector) {
  17. // get existing href and target
  18. if (this.$element.attr('href')) {
  19. this.options.href = this.$element.attr('href');
  20. this.$element.removeAttr('href');
  21. if (this.$element.attr('target')) {
  22. this.options.target = this.$element.attr('target');
  23. }
  24. }
  25. // cancel original event
  26. this.$element.on(that.options.trigger, function(e, ack) {
  27. if (!ack) {
  28. e.preventDefault();
  29. e.stopPropagation();
  30. e.stopImmediatePropagation();
  31. }
  32. });
  33. // trigger original event on confirm
  34. this.$element.on('confirmed.bs.confirmation', function(e) {
  35. $(this).trigger(that.options.trigger, [true]);
  36. });
  37. // manage singleton
  38. this.$element.on('show.bs.confirmation', function(e) {
  39. if (that.options.singleton) {
  40. // close all other popover already initialized
  41. $(that.options._selector).not($(this)).filter(function() {
  42. return $(this).data('bs.confirmation') !== undefined;
  43. }).confirmation('hide');
  44. }
  45. });
  46. }
  47. if (!this.options._isDelegate) {
  48. // manage popout
  49. this.eventBody = false;
  50. this.uid = this.$element[0].id || this.getUID('group_');
  51. this.$element.on('shown.bs.confirmation', function(e) {
  52. if (that.options.popout && !that.eventBody) {
  53. var $this = $(this);
  54. that.eventBody = $('body').on('click.bs.confirmation.'+that.uid, function(e) {
  55. if ($(that.options._selector).is(e.target)) {
  56. return;
  57. }
  58. // close all popover already initialized
  59. $(that.options._selector).filter(function() {
  60. return $(this).data('bs.confirmation') !== undefined;
  61. }).confirmation('hide');
  62. $('body').off('click.bs.'+that.uid);
  63. that.eventBody = false;
  64. });
  65. }
  66. });
  67. }
  68. };
  69. Confirmation.DEFAULTS = $.extend({}, $.fn.popover.Constructor.DEFAULTS, {
  70. placement: 'top',
  71. title: 'Are you sure?',
  72. html: true,
  73. href: false,
  74. popout: false,
  75. singleton: false,
  76. target: '_self',
  77. onConfirm: $.noop,
  78. onCancel: $.noop,
  79. btnOkClass: 'btn-xs btn-primary',
  80. btnOkIcon: 'glyphicon glyphicon-ok',
  81. btnOkLabel: 'Yes',
  82. btnCancelClass: 'btn-xs btn-default',
  83. btnCancelIcon: 'glyphicon glyphicon-remove',
  84. btnCancelLabel: 'No',
  85. template:
  86. '<div class="popover confirmation">' +
  87. '<div class="arrow"></div>' +
  88. '<h3 class="popover-title"></h3>' +
  89. '<div class="popover-content text-center">'+
  90. '<div class="btn-group">'+
  91. '<a class="btn" data-apply="confirmation"></a>'+
  92. '<a class="btn" data-dismiss="confirmation"></a>'+
  93. '</div>'+
  94. '</div>'+
  95. '</div>'
  96. });
  97. Confirmation.prototype = $.extend({}, $.fn.popover.Constructor.prototype);
  98. Confirmation.prototype.constructor = Confirmation;
  99. Confirmation.prototype.getDefaults = function () {
  100. return Confirmation.DEFAULTS;
  101. };
  102. // custom init keeping trace of selectors
  103. Confirmation.prototype.init = function(type, element, options) {
  104. $.fn.popover.Constructor.prototype.init.call(this, type, element, options);
  105. this.options._isDelegate = false;
  106. if (options.selector) { // container of buttons
  107. this.options._selector = this._options._selector = options._root_selector +' '+ options.selector;
  108. }
  109. else if (options._selector) { // children of container
  110. this.options._selector = options._selector;
  111. this.options._isDelegate = true;
  112. }
  113. else { // standalone
  114. this.options._selector = options._root_selector;
  115. }
  116. };
  117. Confirmation.prototype.setContent = function () {
  118. var that = this,
  119. $tip = this.tip(),
  120. o = this.options;
  121. $tip.find('.popover-title')[o.html ? 'html' : 'text'](this.getTitle());
  122. // configure 'ok' button
  123. $tip.find('[data-apply="confirmation"]')
  124. .addClass(o.btnOkClass)
  125. .html(o.btnOkLabel)
  126. .prepend($('<i></i>').addClass(o.btnOkIcon), ' ')
  127. .off('click')
  128. .one('click', function(e) {
  129. that.getOnConfirm.call(that).call(that.$element);
  130. that.$element.trigger('confirmed.bs.confirmation');
  131. that.leave(that);
  132. });
  133. // add href to confirm button if needed
  134. if (o.href && o.href != "#") {
  135. $tip.find('[data-apply="confirmation"]').attr({
  136. href: o.href,
  137. target: o.target
  138. });
  139. }
  140. // configure 'cancel' button
  141. $tip.find('[data-dismiss="confirmation"]')
  142. .addClass(o.btnCancelClass)
  143. .html(o.btnCancelLabel)
  144. .prepend($('<i></i>').addClass(o.btnCancelIcon), ' ')
  145. .off('click')
  146. .one('click', function(e) {
  147. that.getOnCancel.call(that).call(that.$element);
  148. that.$element.trigger('canceled.bs.confirmation');
  149. that.leave(that);
  150. });
  151. $tip.removeClass('fade top bottom left right in');
  152. // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
  153. // this manually by checking the contents.
  154. if (!$tip.find('.popover-title').html()) {
  155. $tip.find('.popover-title').hide();
  156. }
  157. };
  158. Confirmation.prototype.getOnConfirm = function() {
  159. if (this.$element.attr('data-on-confirm')) {
  160. return getFunctionFromString(this.$element.attr('data-on-confirm'));
  161. }
  162. else {
  163. return this.options.onConfirm;
  164. }
  165. };
  166. Confirmation.prototype.getOnCancel = function() {
  167. if (this.$element.attr('data-on-cancel')) {
  168. return getFunctionFromString(this.$element.attr('data-on-cancel'));
  169. }
  170. else {
  171. return this.options.onCancel;
  172. }
  173. };
  174. /*
  175. * Generates an anonymous function from a function name
  176. * function name may contain dots (.) to navigate through objects
  177. * root context is window
  178. */
  179. function getFunctionFromString(functionName) {
  180. var context = window,
  181. namespaces = functionName.split('.'),
  182. func = namespaces.pop();
  183. for (var i=0, l=namespaces.length; i<l; i++) {
  184. context = context[namespaces[i]];
  185. }
  186. return function() {
  187. context[func].call(this);
  188. };
  189. }
  190. // CONFIRMATION PLUGIN DEFINITION
  191. // =========================
  192. var old = $.fn.confirmation;
  193. $.fn.confirmation = function (option) {
  194. var options = (typeof option == 'object' && option) || {};
  195. options._root_selector = this.selector;
  196. return this.each(function () {
  197. var $this = $(this),
  198. data = $this.data('bs.confirmation');
  199. if (!data && option == 'destroy') {
  200. return;
  201. }
  202. if (!data) {
  203. $this.data('bs.confirmation', (data = new Confirmation(this, options)));
  204. }
  205. if (typeof option == 'string') {
  206. data[option]();
  207. }
  208. });
  209. };
  210. $.fn.confirmation.Constructor = Confirmation;
  211. // CONFIRMATION NO CONFLICT
  212. // ===================
  213. $.fn.confirmation.noConflict = function () {
  214. $.fn.confirmation = old;
  215. return this;
  216. };
  217. }(jQuery));