PageRenderTime 89ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/webapp/static/js/bootstrap-confirmation.js

https://bitbucket.org/dangnhaprotrain/co-so-gia-cam-nguyen-thi-hoa
JavaScript | 457 lines | 315 code | 68 blank | 74 comment | 65 complexity | 5b7f2efe7456112bf66064207bdd80be MD5 | raw file
  1. /*!
  2. * Bootstrap Confirmation
  3. * Copyright 2013 Nimit Suwannagate <ethaizone@hotmail.com>
  4. * Copyright 2014-2017 Damien "Mistic" Sorel <contact@git.strangeplanet.fr>
  5. * Licensed under the Apache License, Version 2.0
  6. */
  7. (function($) {
  8. 'use strict';
  9. var activeConfirmation;
  10. // Confirmation extends popover.js
  11. if (!$.fn.popover) {
  12. throw new Error('Confirmation requires popover.js');
  13. }
  14. // CONFIRMATION PUBLIC CLASS DEFINITION
  15. // ===============================
  16. var Confirmation = function(element, options) {
  17. options.trigger = 'click';
  18. this.init(element, options);
  19. };
  20. Confirmation.VERSION = '2.4.0';
  21. /**
  22. * Map between keyboard events "keyCode|which" and "key"
  23. */
  24. Confirmation.KEYMAP = {
  25. 13: 'Enter',
  26. 27: 'Escape',
  27. 39: 'ArrowRight',
  28. 40: 'ArrowDown'
  29. };
  30. Confirmation.DEFAULTS = $.extend({}, $.fn.popover.Constructor.DEFAULTS, {
  31. placement: 'top',
  32. title: 'Are you sure?',
  33. popout: false,
  34. singleton: false,
  35. copyAttributes: 'href target',
  36. buttons: null,
  37. onConfirm: $.noop,
  38. onCancel: $.noop,
  39. btnOkClass: 'btn-xs btn-primary',
  40. btnOkIcon: 'glyphicon glyphicon-ok',
  41. btnOkLabel: 'Yes',
  42. btnCancelClass: 'btn-xs btn-default',
  43. btnCancelIcon: 'glyphicon glyphicon-remove',
  44. btnCancelLabel: 'No',
  45. // @formatter:off
  46. // href="#" allows the buttons to be focused
  47. template: '<div class="popover confirmation">' +
  48. '<div class="arrow"></div>' +
  49. '<h3 class="popover-title"></h3>' +
  50. '<div class="popover-content">' +
  51. '<p class="confirmation-content"></p>' +
  52. '<div class="confirmation-buttons text-center">' +
  53. '<div class="btn-group">' +
  54. '<a href="#" class="btn" data-apply="confirmation"></a>' +
  55. '<a href="#" class="btn" data-dismiss="confirmation"></a>' +
  56. '</div>' +
  57. '</div>' +
  58. '</div>' +
  59. '</div>'
  60. // @formatter:on
  61. });
  62. Confirmation.prototype = $.extend({}, $.fn.popover.Constructor.prototype);
  63. Confirmation.prototype.constructor = Confirmation;
  64. /**
  65. * Expose defaults
  66. * @returns {object}
  67. */
  68. Confirmation.prototype.getDefaults = function() {
  69. return Confirmation.DEFAULTS;
  70. };
  71. /**
  72. * Init the component
  73. * @param element {jQuery}
  74. * @param options {object}
  75. */
  76. Confirmation.prototype.init = function(element, options) {
  77. $.fn.popover.Constructor.prototype.init.call(this, 'confirmation', element, options);
  78. if ((this.options.popout || this.options.singleton) && !options.rootSelector) {
  79. throw new Error('The rootSelector option is required to use popout and singleton features since jQuery 3.');
  80. }
  81. // keep trace of selectors
  82. this.options._isDelegate = false;
  83. if (options.selector) { // container of buttons
  84. this.options._selector = this._options._selector = options.rootSelector + ' ' + options.selector;
  85. }
  86. else if (options._selector) { // children of container
  87. this.options._selector = options._selector;
  88. this.options._isDelegate = true;
  89. }
  90. else { // standalone
  91. this.options._selector = options.rootSelector;
  92. }
  93. var self = this;
  94. if (!this.options.selector) {
  95. // store copied attributes
  96. this.options._attributes = {};
  97. if (this.options.copyAttributes) {
  98. if (typeof this.options.copyAttributes === 'string') {
  99. this.options.copyAttributes = this.options.copyAttributes.split(' ');
  100. }
  101. }
  102. else {
  103. this.options.copyAttributes = [];
  104. }
  105. this.options.copyAttributes.forEach(function(attr) {
  106. this.options._attributes[attr] = this.$element.attr(attr);
  107. }, this);
  108. // cancel original event
  109. this.$element.on(this.options.trigger, function(e, ack) {
  110. if (!ack) {
  111. e.preventDefault();
  112. e.stopPropagation();
  113. e.stopImmediatePropagation();
  114. }
  115. });
  116. // manage singleton
  117. this.$element.on('show.bs.confirmation', function(e) {
  118. if (self.options.singleton) {
  119. // close all other popover already initialized
  120. $(self.options._selector).not($(this)).filter(function() {
  121. return $(this).data('bs.confirmation') !== undefined;
  122. }).confirmation('hide');
  123. }
  124. });
  125. }
  126. else {
  127. // cancel original event
  128. this.$element.on(this.options.trigger, this.options.selector, function(e, ack) {
  129. if (!ack) {
  130. e.preventDefault();
  131. e.stopPropagation();
  132. e.stopImmediatePropagation();
  133. }
  134. });
  135. }
  136. if (!this.options._isDelegate) {
  137. // manage popout
  138. this.eventBody = false;
  139. this.uid = this.$element[0].id || this.getUID('group_');
  140. this.$element.on('shown.bs.confirmation', function(e) {
  141. if (self.options.popout && !self.eventBody) {
  142. self.eventBody = $('body').on('click.bs.confirmation.' + self.uid, function(e) {
  143. if ($(self.options._selector).is(e.target)) {
  144. return;
  145. }
  146. // close all popover already initialized
  147. $(self.options._selector).filter(function() {
  148. return $(this).data('bs.confirmation') !== undefined;
  149. }).confirmation('hide');
  150. $('body').off('click.bs.' + self.uid);
  151. self.eventBody = false;
  152. });
  153. }
  154. });
  155. }
  156. };
  157. /**
  158. * Overrides, always show
  159. * @returns {boolean}
  160. */
  161. Confirmation.prototype.hasContent = function() {
  162. return true;
  163. };
  164. /**
  165. * Sets the popover content
  166. */
  167. Confirmation.prototype.setContent = function() {
  168. var self = this;
  169. var $tip = this.tip();
  170. var title = this.getTitle();
  171. var content = this.getContent();
  172. $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title);
  173. $tip.find('.confirmation-content').toggle(!!content).children().detach().end()[
  174. // we use append for html objects to maintain js events
  175. this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
  176. ](content);
  177. $tip.on('click', function(e) {
  178. e.stopPropagation();
  179. });
  180. if (this.options.buttons) {
  181. // configure custom buttons
  182. var $group = $tip.find('.confirmation-buttons .btn-group').empty();
  183. this.options.buttons.forEach(function(button) {
  184. $group.append(
  185. $('<a href="#"></a>')
  186. .addClass(button.class || 'btn btn-xs btn-default')
  187. .html(button.label || '')
  188. .attr(button.attr || {})
  189. .prepend($('<i></i>').addClass(button.icon), ' ')
  190. .one('click', function(e) {
  191. if ($(this).attr('href') === '#') {
  192. e.preventDefault();
  193. }
  194. if (button.onClick) {
  195. button.onClick.call(self.$element);
  196. }
  197. if (button.cancel) {
  198. self.getOnCancel().call(self.$element, button.value);
  199. self.$element.trigger('canceled.bs.confirmation', [button.value]);
  200. }
  201. else {
  202. self.getOnConfirm().call(self.$element, button.value);
  203. self.$element.trigger('confirmed.bs.confirmation', [button.value]);
  204. }
  205. if (self.inState) { // Bootstrap 3.3.5
  206. self.inState.click = false;
  207. }
  208. self.hide();
  209. })
  210. );
  211. }, this);
  212. }
  213. else {
  214. // configure 'ok' button
  215. $tip.find('[data-apply="confirmation"]')
  216. .addClass(this.options.btnOkClass)
  217. .html(this.options.btnOkLabel)
  218. .attr(this.options._attributes)
  219. .prepend($('<i></i>').addClass(this.options.btnOkIcon), ' ')
  220. .off('click')
  221. .one('click', function(e) {
  222. if ($(this).attr('href') === '#') {
  223. e.preventDefault();
  224. }
  225. self.getOnConfirm().call(self.$element);
  226. self.$element.trigger('confirmed.bs.confirmation');
  227. self.$element.trigger(self.options.trigger, [true]);
  228. self.hide();
  229. });
  230. // configure 'cancel' button
  231. $tip.find('[data-dismiss="confirmation"]')
  232. .addClass(this.options.btnCancelClass)
  233. .html(this.options.btnCancelLabel)
  234. .prepend($('<i></i>').addClass(this.options.btnCancelIcon), ' ')
  235. .off('click')
  236. .one('click', function(e) {
  237. e.preventDefault();
  238. self.getOnCancel().call(self.$element);
  239. self.$element.trigger('canceled.bs.confirmation');
  240. if (self.inState) { // Bootstrap 3.3.5
  241. self.inState.click = false;
  242. }
  243. self.hide();
  244. });
  245. }
  246. $tip.removeClass('fade top bottom left right in');
  247. // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
  248. // this manually by checking the contents.
  249. if (!$tip.find('.popover-title').html()) {
  250. $tip.find('.popover-title').hide();
  251. }
  252. // bind key navigation
  253. activeConfirmation = this;
  254. $(window)
  255. .off('keyup.bs.confirmation')
  256. .on('keyup.bs.confirmation', this._onKeyup.bind(this));
  257. };
  258. /**
  259. * Remove key binding on destroy
  260. */
  261. Confirmation.prototype.destroy = function() {
  262. if (activeConfirmation === this) {
  263. activeConfirmation = undefined;
  264. $(window).off('keyup.bs.confirmation');
  265. }
  266. $.fn.popover.Constructor.prototype.destroy.call(this);
  267. };
  268. /**
  269. * Remove key binding on hide
  270. */
  271. Confirmation.prototype.hide = function() {
  272. if (activeConfirmation === this) {
  273. activeConfirmation = undefined;
  274. $(window).off('keyup.bs.confirmation');
  275. }
  276. $.fn.popover.Constructor.prototype.hide.call(this);
  277. };
  278. /**
  279. * Navigate through buttons with keyboard
  280. * @param event
  281. * @private
  282. */
  283. Confirmation.prototype._onKeyup = function(event) {
  284. if (!this.$tip) {
  285. activeConfirmation = undefined;
  286. $(window).off('keyup.bs.confirmation');
  287. return;
  288. }
  289. var key = event.key || Confirmation.KEYMAP[event.keyCode || event.which];
  290. var $group = this.$tip.find('.confirmation-buttons .btn-group');
  291. var $active = $group.find('.active');
  292. var $next;
  293. switch (key) {
  294. case 'Escape':
  295. this.hide();
  296. break;
  297. case 'ArrowRight':
  298. if ($active.length && $active.next().length) {
  299. $next = $active.next();
  300. }
  301. else {
  302. $next = $group.children().first();
  303. }
  304. $active.removeClass('active');
  305. $next.addClass('active').focus();
  306. break;
  307. case 'ArrowLeft':
  308. if ($active.length && $active.prev().length) {
  309. $next = $active.prev();
  310. }
  311. else {
  312. $next = $group.children().last();
  313. }
  314. $active.removeClass('active');
  315. $next.addClass('active').focus();
  316. break;
  317. }
  318. };
  319. /**
  320. * Gets the on-confirm callback
  321. * @returns {function}
  322. */
  323. Confirmation.prototype.getOnConfirm = function() {
  324. if (this.$element.attr('data-on-confirm')) {
  325. return getFunctionFromString(this.$element.attr('data-on-confirm'));
  326. }
  327. else {
  328. return this.options.onConfirm;
  329. }
  330. };
  331. /**
  332. * Gets the on-cancel callback
  333. * @returns {function}
  334. */
  335. Confirmation.prototype.getOnCancel = function() {
  336. if (this.$element.attr('data-on-cancel')) {
  337. return getFunctionFromString(this.$element.attr('data-on-cancel'));
  338. }
  339. else {
  340. return this.options.onCancel;
  341. }
  342. };
  343. /**
  344. * Generates an anonymous function from a function name
  345. * function name may contain dots (.) to navigate through objects
  346. * root context is window
  347. */
  348. function getFunctionFromString(functionName) {
  349. var context = window;
  350. var namespaces = functionName.split('.');
  351. var func = namespaces.pop();
  352. for (var i = 0, l = namespaces.length; i < l; i++) {
  353. context = context[namespaces[i]];
  354. }
  355. return function() {
  356. context[func].call(this);
  357. };
  358. }
  359. // CONFIRMATION PLUGIN DEFINITION
  360. // =========================
  361. var old = $.fn.confirmation;
  362. $.fn.confirmation = function(option) {
  363. var options = (typeof option == 'object' && option) || {};
  364. options.rootSelector = this.selector || options.rootSelector; // this.selector removed in jQuery > 3
  365. return this.each(function() {
  366. var $this = $(this);
  367. var data = $this.data('bs.confirmation');
  368. if (!data && option == 'destroy') {
  369. return;
  370. }
  371. if (!data) {
  372. $this.data('bs.confirmation', (data = new Confirmation(this, options)));
  373. }
  374. if (typeof option == 'string') {
  375. data[option]();
  376. if (option == 'hide' && data.inState) { //data.inState doesn't exist in Bootstrap < 3.3.5
  377. data.inState.click = false;
  378. }
  379. }
  380. });
  381. };
  382. $.fn.confirmation.Constructor = Confirmation;
  383. // CONFIRMATION NO CONFLICT
  384. // ===================
  385. $.fn.confirmation.noConflict = function() {
  386. $.fn.confirmation = old;
  387. return this;
  388. };
  389. }(jQuery));