jquery-confirm.js 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379
  1. /*!
  2. * jquery-confirm v3.3.4 (http://craftpip.github.io/jquery-confirm/)
  3. * Author: Boniface Pereira
  4. * Website: www.craftpip.com
  5. * Contact: hey@craftpip.com
  6. *
  7. * Copyright 2013-2019 jquery-confirm
  8. * Licensed under MIT (https://github.com/craftpip/jquery-confirm/blob/master/LICENSE)
  9. */
  10. /**
  11. * UMD (Universal Module Definition) to support CommonJS, AMD and browser
  12. * Thanks to https://github.com/umdjs/umd
  13. */
  14. (function(factory){
  15. if(typeof define === 'function' && define.amd){
  16. // AMD. Register as an anonymous module.
  17. define(['jquery'], factory);
  18. }else if(typeof module === 'object' && module.exports){
  19. // Node/CommonJS
  20. module.exports = function(root, jQuery){
  21. if(jQuery === undefined){
  22. // require('jQuery') returns a factory that requires window to
  23. // build a jQuery instance, we normalize how we use modules
  24. // that require this pattern but the window provided is a noop
  25. // if it's defined (how jquery works)
  26. if(typeof window !== 'undefined'){
  27. jQuery = require('jquery');
  28. }
  29. else{
  30. jQuery = require('jquery')(root);
  31. }
  32. }
  33. factory(jQuery);
  34. return jQuery;
  35. };
  36. }else{
  37. // Browser globals
  38. factory(jQuery);
  39. }
  40. }(function($){
  41. "use strict";
  42. // locally assign window
  43. var w = window;
  44. // w.jconfirm
  45. // w.Jconfirm;
  46. $.fn.confirm = function(options, option2){
  47. if(typeof options === 'undefined') options = {};
  48. if(typeof options === 'string'){
  49. options = {
  50. content: options,
  51. title: (option2) ? option2 : false
  52. };
  53. }
  54. /*
  55. * Alias of $.confirm to emulate native confirm()
  56. */
  57. $(this).each(function(){
  58. var $this = $(this);
  59. if($this.attr('jc-attached')){
  60. console.warn('jConfirm has already been attached to this element ', $this[0]);
  61. return;
  62. }
  63. $this.on('click', function(e){
  64. e.preventDefault();
  65. var jcOption = $.extend({}, options);
  66. if($this.attr('data-title'))
  67. jcOption['title'] = $this.attr('data-title');
  68. if($this.attr('data-content'))
  69. jcOption['content'] = $this.attr('data-content');
  70. if(typeof jcOption['buttons'] === 'undefined')
  71. jcOption['buttons'] = {};
  72. jcOption['$target'] = $this;
  73. if($this.attr('href') && Object.keys(jcOption['buttons']).length === 0){
  74. var buttons = $.extend(true, {}, w.jconfirm.pluginDefaults.defaultButtons, (w.jconfirm.defaults || {}).defaultButtons || {});
  75. var firstBtn = Object.keys(buttons)[0];
  76. jcOption['buttons'] = buttons;
  77. jcOption.buttons[firstBtn].action = function(){
  78. location.href = $this.attr('href');
  79. };
  80. }
  81. jcOption['closeIcon'] = false;
  82. var instance = $.confirm(jcOption);
  83. });
  84. $this.attr('jc-attached', true);
  85. });
  86. return $(this);
  87. };
  88. $.confirm = function(options, option2){
  89. if(typeof options === 'undefined') options = {};
  90. if(typeof options === 'string'){
  91. options = {
  92. content: options,
  93. title: (option2) ? option2 : false
  94. };
  95. }
  96. var putDefaultButtons = !(options['buttons'] === false);
  97. if(typeof options['buttons'] !== 'object')
  98. options['buttons'] = {};
  99. if(Object.keys(options['buttons']).length === 0 && putDefaultButtons){
  100. var buttons = $.extend(true, {}, w.jconfirm.pluginDefaults.defaultButtons, (w.jconfirm.defaults || {}).defaultButtons || {});
  101. options['buttons'] = buttons;
  102. }
  103. /*
  104. * Alias of jconfirm
  105. */
  106. return w.jconfirm(options);
  107. };
  108. $.alert = function(options, option2){
  109. if(typeof options === 'undefined') options = {};
  110. if(typeof options === 'string'){
  111. options = {
  112. content: options,
  113. title: (option2) ? option2 : false
  114. };
  115. }
  116. var putDefaultButtons = !(options['buttons'] === false);
  117. if(typeof options.buttons !== 'object')
  118. options.buttons = {};
  119. if(Object.keys(options['buttons']).length === 0 && putDefaultButtons){
  120. var buttons = $.extend(true, {}, w.jconfirm.pluginDefaults.defaultButtons, (w.jconfirm.defaults || {}).defaultButtons || {});
  121. var firstBtn = Object.keys(buttons)[0];
  122. options['buttons'][firstBtn] = buttons[firstBtn];
  123. }
  124. /*
  125. * Alias of jconfirm
  126. */
  127. return w.jconfirm(options);
  128. };
  129. $.dialog = function(options, option2){
  130. if(typeof options === 'undefined') options = {};
  131. if(typeof options === 'string'){
  132. options = {
  133. content: options,
  134. title: (option2) ? option2 : false,
  135. closeIcon: function(){
  136. // Just close the modal
  137. }
  138. };
  139. }
  140. options['buttons'] = {}; // purge buttons
  141. if(typeof options['closeIcon'] === 'undefined'){
  142. // Dialog must have a closeIcon.
  143. options['closeIcon'] = function(){
  144. }
  145. }
  146. /*
  147. * Alias of jconfirm
  148. */
  149. options.confirmKeys = [13];
  150. return w.jconfirm(options);
  151. };
  152. w.jconfirm = function(options){
  153. if(typeof options === 'undefined') options = {};
  154. /*
  155. * initial function for calling.
  156. */
  157. var pluginOptions = $.extend(true, {}, w.jconfirm.pluginDefaults);
  158. if(w.jconfirm.defaults){
  159. pluginOptions = $.extend(true, pluginOptions, w.jconfirm.defaults);
  160. }
  161. /*
  162. * merge options with plugin defaults.
  163. */
  164. pluginOptions = $.extend(true, {}, pluginOptions, options);
  165. var instance = new w.Jconfirm(pluginOptions);
  166. w.jconfirm.instances.push(instance);
  167. return instance;
  168. };
  169. w.Jconfirm = function(options){
  170. /*
  171. * constructor function Jconfirm,
  172. * options = user options.
  173. */
  174. $.extend(this, options);
  175. this._init();
  176. };
  177. w.Jconfirm.prototype = {
  178. _init: function(){
  179. var that = this;
  180. if(!w.jconfirm.instances.length)
  181. w.jconfirm.lastFocused = $('body').find(':focus');
  182. this._id = Math.round(Math.random() * 99999);
  183. /**
  184. * contentParsed maintains the contents for $content, before it is put in DOM
  185. */
  186. this.contentParsed = $(document.createElement('div'));
  187. if(!this.lazyOpen){
  188. setTimeout(function(){
  189. that.open();
  190. }, 0);
  191. }
  192. },
  193. _buildHTML: function(){
  194. var that = this;
  195. // prefix the animation string and store in animationParsed
  196. this._parseAnimation(this.animation, 'o');
  197. this._parseAnimation(this.closeAnimation, 'c');
  198. this._parseBgDismissAnimation(this.backgroundDismissAnimation);
  199. this._parseColumnClass(this.columnClass);
  200. this._parseTheme(this.theme);
  201. this._parseType(this.type);
  202. /*
  203. * Append html.
  204. */
  205. var template = $(this.template);
  206. template.find('.jconfirm-box').addClass(this.animationParsed).addClass(this.backgroundDismissAnimationParsed).addClass(this.typeParsed);
  207. if(this.typeAnimated)
  208. template.find('.jconfirm-box').addClass('jconfirm-type-animated');
  209. if(this.useBootstrap){
  210. template.find('.jc-bs3-row').addClass(this.bootstrapClasses.row);
  211. template.find('.jc-bs3-row').addClass('justify-content-md-center justify-content-sm-center justify-content-xs-center justify-content-lg-center');
  212. template.find('.jconfirm-box-container').addClass(this.columnClassParsed);
  213. if(this.containerFluid)
  214. template.find('.jc-bs3-container').addClass(this.bootstrapClasses.containerFluid);
  215. else
  216. template.find('.jc-bs3-container').addClass(this.bootstrapClasses.container);
  217. }else{
  218. template.find('.jconfirm-box').css('width', this.boxWidth);
  219. }
  220. if(this.titleClass)
  221. template.find('.jconfirm-title-c').addClass(this.titleClass);
  222. template.addClass(this.themeParsed);
  223. var ariaLabel = 'jconfirm-box' + this._id;
  224. template.find('.jconfirm-box').attr('aria-labelledby', ariaLabel).attr('tabindex', -1);
  225. template.find('.jconfirm-content').attr('id', ariaLabel);
  226. if(this.bgOpacity !== null)
  227. template.find('.jconfirm-bg').css('opacity', this.bgOpacity);
  228. if(this.rtl)
  229. template.addClass('jconfirm-rtl');
  230. this.$el = template.appendTo(this.container);
  231. this.$jconfirmBoxContainer = this.$el.find('.jconfirm-box-container');
  232. this.$jconfirmBox = this.$body = this.$el.find('.jconfirm-box');
  233. this.$jconfirmBg = this.$el.find('.jconfirm-bg');
  234. this.$title = this.$el.find('.jconfirm-title');
  235. this.$titleContainer = this.$el.find('.jconfirm-title-c');
  236. this.$content = this.$el.find('div.jconfirm-content');
  237. this.$contentPane = this.$el.find('.jconfirm-content-pane');
  238. this.$icon = this.$el.find('.jconfirm-icon-c');
  239. this.$closeIcon = this.$el.find('.jconfirm-closeIcon');
  240. this.$holder = this.$el.find('.jconfirm-holder');
  241. // this.$content.css(this._getCSS(this.animationSpeed, this.animationBounce));
  242. this.$btnc = this.$el.find('.jconfirm-buttons');
  243. this.$scrollPane = this.$el.find('.jconfirm-scrollpane');
  244. that.setStartingPoint();
  245. // for loading content via URL
  246. this._contentReady = $.Deferred();
  247. this._modalReady = $.Deferred();
  248. this.$holder.css({
  249. 'padding-top': this.offsetTop,
  250. 'padding-bottom': this.offsetBottom,
  251. });
  252. this.setTitle();
  253. this.setIcon();
  254. this._setButtons();
  255. this._parseContent();
  256. this.initDraggable();
  257. if(this.isAjax)
  258. this.showLoading(false);
  259. $.when(this._contentReady, this._modalReady).then(function(){
  260. if(that.isAjaxLoading)
  261. setTimeout(function(){
  262. that.isAjaxLoading = false;
  263. that.setContent();
  264. that.setTitle();
  265. that.setIcon();
  266. setTimeout(function(){
  267. that.hideLoading(false);
  268. that._updateContentMaxHeight();
  269. }, 100);
  270. if(typeof that.onContentReady === 'function')
  271. that.onContentReady();
  272. }, 50);
  273. else{
  274. // that.setContent();
  275. that._updateContentMaxHeight();
  276. that.setTitle();
  277. that.setIcon();
  278. if(typeof that.onContentReady === 'function')
  279. that.onContentReady();
  280. }
  281. // start countdown after content has loaded.
  282. if(that.autoClose)
  283. that._startCountDown();
  284. }).then(function(){
  285. that._watchContent();
  286. });
  287. if(this.animation === 'none'){
  288. this.animationSpeed = 1;
  289. this.animationBounce = 1;
  290. }
  291. this.$body.css(this._getCSS(this.animationSpeed, this.animationBounce));
  292. this.$contentPane.css(this._getCSS(this.animationSpeed, 1));
  293. this.$jconfirmBg.css(this._getCSS(this.animationSpeed, 1));
  294. this.$jconfirmBoxContainer.css(this._getCSS(this.animationSpeed, 1));
  295. },
  296. _typePrefix: 'jconfirm-type-',
  297. typeParsed: '',
  298. _parseType: function(type){
  299. this.typeParsed = this._typePrefix + type;
  300. },
  301. setType: function(type){
  302. var oldClass = this.typeParsed;
  303. this._parseType(type);
  304. this.$jconfirmBox.removeClass(oldClass).addClass(this.typeParsed);
  305. },
  306. themeParsed: '',
  307. _themePrefix: 'jconfirm-',
  308. setTheme: function(theme){
  309. var previous = this.theme;
  310. this.theme = theme || this.theme;
  311. this._parseTheme(this.theme);
  312. if(previous)
  313. this.$el.removeClass(previous);
  314. this.$el.addClass(this.themeParsed);
  315. this.theme = theme;
  316. },
  317. _parseTheme: function(theme){
  318. var that = this;
  319. theme = theme.split(',');
  320. $.each(theme, function(k, a){
  321. if(a.indexOf(that._themePrefix) === -1)
  322. theme[k] = that._themePrefix + $.trim(a);
  323. });
  324. this.themeParsed = theme.join(' ').toLowerCase();
  325. },
  326. backgroundDismissAnimationParsed: '',
  327. _bgDismissPrefix: 'jconfirm-hilight-',
  328. _parseBgDismissAnimation: function(bgDismissAnimation){
  329. var animation = bgDismissAnimation.split(',');
  330. var that = this;
  331. $.each(animation, function(k, a){
  332. if(a.indexOf(that._bgDismissPrefix) === -1)
  333. animation[k] = that._bgDismissPrefix + $.trim(a);
  334. });
  335. this.backgroundDismissAnimationParsed = animation.join(' ').toLowerCase();
  336. },
  337. animationParsed: '',
  338. closeAnimationParsed: '',
  339. _animationPrefix: 'jconfirm-animation-',
  340. setAnimation: function(animation){
  341. this.animation = animation || this.animation;
  342. this._parseAnimation(this.animation, 'o');
  343. },
  344. _parseAnimation: function(animation, which){
  345. which = which || 'o'; // parse what animation and store where. open or close?
  346. var animations = animation.split(',');
  347. var that = this;
  348. $.each(animations, function(k, a){
  349. if(a.indexOf(that._animationPrefix) === -1)
  350. animations[k] = that._animationPrefix + $.trim(a);
  351. });
  352. var a_string = animations.join(' ').toLowerCase();
  353. if(which === 'o')
  354. this.animationParsed = a_string;
  355. else
  356. this.closeAnimationParsed = a_string;
  357. return a_string;
  358. },
  359. setCloseAnimation: function(closeAnimation){
  360. this.closeAnimation = closeAnimation || this.closeAnimation;
  361. this._parseAnimation(this.closeAnimation, 'c');
  362. },
  363. setAnimationSpeed: function(speed){
  364. this.animationSpeed = speed || this.animationSpeed;
  365. // this.$body.css(this._getCSS(this.animationSpeed, this.animationBounce));
  366. },
  367. columnClassParsed: '',
  368. setColumnClass: function(colClass){
  369. if(!this.useBootstrap){
  370. console.warn("cannot set columnClass, useBootstrap is set to false");
  371. return;
  372. }
  373. this.columnClass = colClass || this.columnClass;
  374. this._parseColumnClass(this.columnClass);
  375. this.$jconfirmBoxContainer.addClass(this.columnClassParsed);
  376. },
  377. _updateContentMaxHeight: function(){
  378. var height = $(window).height() - (this.$jconfirmBox.outerHeight() - this.$contentPane.outerHeight()) - (this.offsetTop + this.offsetBottom);
  379. this.$contentPane.css({
  380. 'max-height': height + 'px'
  381. });
  382. },
  383. setBoxWidth: function(width){
  384. if(this.useBootstrap){
  385. console.warn("cannot set boxWidth, useBootstrap is set to true");
  386. return;
  387. }
  388. this.boxWidth = width;
  389. this.$jconfirmBox.css('width', width);
  390. },
  391. _parseColumnClass: function(colClass){
  392. colClass = colClass.toLowerCase();
  393. var p;
  394. switch(colClass){
  395. case 'xl':
  396. case 'xlarge':
  397. p = 'col-md-12';
  398. break;
  399. case 'l':
  400. case 'large':
  401. p = 'col-md-8 col-md-offset-2';
  402. break;
  403. case 'm':
  404. case 'medium':
  405. p = 'col-md-6 col-md-offset-3';
  406. break;
  407. case 's':
  408. case 'small':
  409. p = 'col-md-4 col-md-offset-4';
  410. break;
  411. case 'xs':
  412. case 'xsmall':
  413. p = 'col-md-2 col-md-offset-5';
  414. break;
  415. default:
  416. p = colClass;
  417. }
  418. this.columnClassParsed = p;
  419. },
  420. initDraggable: function(){
  421. var that = this;
  422. var $t = this.$titleContainer;
  423. this.resetDrag();
  424. if(this.draggable){
  425. $t.on('mousedown', function(e){
  426. $t.addClass('jconfirm-hand');
  427. that.mouseX = e.clientX;
  428. that.mouseY = e.clientY;
  429. that.isDrag = true;
  430. });
  431. $(window).on('mousemove.' + this._id, function(e){
  432. if(that.isDrag){
  433. that.movingX = e.clientX - that.mouseX + that.initialX;
  434. that.movingY = e.clientY - that.mouseY + that.initialY;
  435. that.setDrag();
  436. }
  437. });
  438. $(window).on('mouseup.' + this._id, function(){
  439. $t.removeClass('jconfirm-hand');
  440. if(that.isDrag){
  441. that.isDrag = false;
  442. that.initialX = that.movingX;
  443. that.initialY = that.movingY;
  444. }
  445. })
  446. }
  447. },
  448. resetDrag: function(){
  449. this.isDrag = false;
  450. this.initialX = 0;
  451. this.initialY = 0;
  452. this.movingX = 0;
  453. this.movingY = 0;
  454. this.mouseX = 0;
  455. this.mouseY = 0;
  456. this.$jconfirmBoxContainer.css('transform', 'translate(' + 0 + 'px, ' + 0 + 'px)');
  457. },
  458. setDrag: function(){
  459. if(!this.draggable)
  460. return;
  461. this.alignMiddle = false;
  462. var boxWidth = this.$jconfirmBox.outerWidth();
  463. var boxHeight = this.$jconfirmBox.outerHeight();
  464. var windowWidth = $(window).width();
  465. var windowHeight = $(window).height();
  466. var that = this;
  467. var dragUpdate = 1;
  468. if(that.movingX % dragUpdate === 0 || that.movingY % dragUpdate === 0){
  469. if(that.dragWindowBorder){
  470. var leftDistance = (windowWidth / 2) - boxWidth / 2;
  471. var topDistance = (windowHeight / 2) - boxHeight / 2;
  472. topDistance -= that.dragWindowGap;
  473. leftDistance -= that.dragWindowGap;
  474. if(leftDistance + that.movingX < 0){
  475. that.movingX = -leftDistance;
  476. }else if(leftDistance - that.movingX < 0){
  477. that.movingX = leftDistance;
  478. }
  479. if(topDistance + that.movingY < 0){
  480. that.movingY = -topDistance;
  481. }else if(topDistance - that.movingY < 0){
  482. that.movingY = topDistance;
  483. }
  484. }
  485. that.$jconfirmBoxContainer.css('transform', 'translate(' + that.movingX + 'px, ' + that.movingY + 'px)');
  486. }
  487. },
  488. _scrollTop: function(){
  489. if(typeof pageYOffset !== 'undefined'){
  490. //most browsers except IE before #9
  491. return pageYOffset;
  492. }
  493. else{
  494. var B = document.body; //IE 'quirks'
  495. var D = document.documentElement; //IE with doctype
  496. D = (D.clientHeight) ? D : B;
  497. return D.scrollTop;
  498. }
  499. },
  500. _watchContent: function(){
  501. var that = this;
  502. if(this._timer) clearInterval(this._timer);
  503. var prevContentHeight = 0;
  504. this._timer = setInterval(function(){
  505. if(that.smoothContent){
  506. var contentHeight = that.$content.outerHeight() || 0;
  507. if(contentHeight !== prevContentHeight){
  508. // Commented out to prevent scroll to top when updating the content
  509. // (for example when using ajax in forms in content)
  510. // that.$contentPane.css({
  511. // 'height': contentHeight
  512. // }).scrollTop(0);
  513. prevContentHeight = contentHeight;
  514. }
  515. var wh = $(window).height();
  516. var total = that.offsetTop + that.offsetBottom + that.$jconfirmBox.height() - that.$contentPane.height() + that.$content.height();
  517. if(total < wh){
  518. that.$contentPane.addClass('no-scroll');
  519. }else{
  520. that.$contentPane.removeClass('no-scroll');
  521. }
  522. }
  523. }, this.watchInterval);
  524. },
  525. _overflowClass: 'jconfirm-overflow',
  526. _hilightAnimating: false,
  527. highlight: function(){
  528. this.hiLightModal();
  529. },
  530. hiLightModal: function(){
  531. var that = this;
  532. if(this._hilightAnimating)
  533. return;
  534. that.$body.addClass('hilight');
  535. var duration = parseFloat(that.$body.css('animation-duration')) || 2;
  536. this._hilightAnimating = true;
  537. setTimeout(function(){
  538. that._hilightAnimating = false;
  539. that.$body.removeClass('hilight');
  540. }, duration * 1000);
  541. },
  542. _bindEvents: function(){
  543. var that = this;
  544. this.boxClicked = false;
  545. this.$scrollPane.click(function(e){ // Ignore propagated clicks
  546. if(!that.boxClicked){ // Background clicked
  547. /*
  548. If backgroundDismiss is a function and its return value is truthy
  549. proceed to close the modal.
  550. */
  551. var buttonName = false;
  552. var shouldClose = false;
  553. var str;
  554. if(typeof that.backgroundDismiss === 'function')
  555. str = that.backgroundDismiss();
  556. else
  557. str = that.backgroundDismiss;
  558. if(typeof str === 'string' && typeof that.buttons[str] !== 'undefined'){
  559. buttonName = str;
  560. shouldClose = false;
  561. }else if(typeof str === 'undefined' || !!(str) === true){
  562. shouldClose = true;
  563. }else{
  564. shouldClose = false;
  565. }
  566. if(buttonName){
  567. var btnResponse = that.buttons[buttonName].action.apply(that);
  568. shouldClose = (typeof btnResponse === 'undefined') || !!(btnResponse);
  569. }
  570. if(shouldClose)
  571. that.close();
  572. else
  573. that.hiLightModal();
  574. }
  575. that.boxClicked = false;
  576. });
  577. this.$jconfirmBox.click(function(e){
  578. that.boxClicked = true;
  579. });
  580. var isKeyDown = false;
  581. $(window).on('jcKeyDown.' + that._id, function(e){
  582. if(!isKeyDown){
  583. isKeyDown = true;
  584. }
  585. });
  586. $(window).on('keyup.' + that._id, function(e){
  587. if(isKeyDown){
  588. that.reactOnKey(e);
  589. isKeyDown = false;
  590. }
  591. });
  592. $(window).on('resize.' + this._id, function(){
  593. that._updateContentMaxHeight();
  594. setTimeout(function(){
  595. that.resetDrag();
  596. }, 100);
  597. });
  598. },
  599. _cubic_bezier: '0.36, 0.55, 0.19',
  600. _getCSS: function(speed, bounce){
  601. return {
  602. '-webkit-transition-duration': speed / 1000 + 's',
  603. 'transition-duration': speed / 1000 + 's',
  604. '-webkit-transition-timing-function': 'cubic-bezier(' + this._cubic_bezier + ', ' + bounce + ')',
  605. 'transition-timing-function': 'cubic-bezier(' + this._cubic_bezier + ', ' + bounce + ')'
  606. };
  607. },
  608. _setButtons: function(){
  609. var that = this;
  610. /*
  611. * Settings up buttons
  612. */
  613. var total_buttons = 0;
  614. if(typeof this.buttons !== 'object')
  615. this.buttons = {};
  616. $.each(this.buttons, function(key, button){
  617. total_buttons += 1;
  618. if(typeof button === 'function'){
  619. that.buttons[key] = button = {
  620. action: button
  621. };
  622. }
  623. that.buttons[key].text = button.text || key;
  624. that.buttons[key].btnClass = button.btnClass || 'btn-default';
  625. that.buttons[key].action = button.action || function(){
  626. };
  627. that.buttons[key].keys = button.keys || [];
  628. that.buttons[key].isHidden = button.isHidden || false;
  629. that.buttons[key].isDisabled = button.isDisabled || false;
  630. $.each(that.buttons[key].keys, function(i, a){
  631. that.buttons[key].keys[i] = a.toLowerCase();
  632. });
  633. var button_element = $('<button type="button" class="btn"></button>')
  634. .html(that.buttons[key].text)
  635. .addClass(that.buttons[key].btnClass)
  636. .prop('disabled', that.buttons[key].isDisabled)
  637. .css('display', that.buttons[key].isHidden ? 'none' : '')
  638. .click(function(e){
  639. e.preventDefault();
  640. var res = that.buttons[key].action.apply(that, [that.buttons[key]]);
  641. that.onAction.apply(that, [key, that.buttons[key]]);
  642. that._stopCountDown();
  643. if(typeof res === 'undefined' || res)
  644. that.close();
  645. });
  646. that.buttons[key].el = button_element;
  647. that.buttons[key].setText = function(text){
  648. button_element.html(text);
  649. };
  650. that.buttons[key].addClass = function(className){
  651. button_element.addClass(className);
  652. };
  653. that.buttons[key].removeClass = function(className){
  654. button_element.removeClass(className);
  655. };
  656. that.buttons[key].disable = function(){
  657. that.buttons[key].isDisabled = true;
  658. button_element.prop('disabled', true);
  659. };
  660. that.buttons[key].enable = function(){
  661. that.buttons[key].isDisabled = false;
  662. button_element.prop('disabled', false);
  663. };
  664. that.buttons[key].show = function(){
  665. that.buttons[key].isHidden = false;
  666. button_element.css('display', '');
  667. };
  668. that.buttons[key].hide = function(){
  669. that.buttons[key].isHidden = true;
  670. button_element.css('display', 'none');
  671. };
  672. /*
  673. Buttons are prefixed with $_ or $$ for quick access
  674. */
  675. that['$_' + key] = that['$$' + key] = button_element;
  676. that.$btnc.append(button_element);
  677. });
  678. if(total_buttons === 0) this.$btnc.hide();
  679. if(this.closeIcon === null && total_buttons === 0){
  680. /*
  681. in case when no buttons are present & closeIcon is null, closeIcon is set to true,
  682. set closeIcon to true to explicitly tell to hide the close icon
  683. */
  684. this.closeIcon = true;
  685. }
  686. if(this.closeIcon){
  687. if(this.closeIconClass){
  688. // user requires a custom class.
  689. var closeHtml = '<i class="' + this.closeIconClass + '"></i>';
  690. this.$closeIcon.html(closeHtml);
  691. }
  692. this.$closeIcon.click(function(e){
  693. e.preventDefault();
  694. var buttonName = false;
  695. var shouldClose = false;
  696. var str;
  697. if(typeof that.closeIcon === 'function'){
  698. str = that.closeIcon();
  699. }else{
  700. str = that.closeIcon;
  701. }
  702. if(typeof str === 'string' && typeof that.buttons[str] !== 'undefined'){
  703. buttonName = str;
  704. shouldClose = false;
  705. }else if(typeof str === 'undefined' || !!(str) === true){
  706. shouldClose = true;
  707. }else{
  708. shouldClose = false;
  709. }
  710. if(buttonName){
  711. var btnResponse = that.buttons[buttonName].action.apply(that);
  712. shouldClose = (typeof btnResponse === 'undefined') || !!(btnResponse);
  713. }
  714. if(shouldClose){
  715. that.close();
  716. }
  717. });
  718. this.$closeIcon.show();
  719. }else{
  720. this.$closeIcon.hide();
  721. }
  722. },
  723. setTitle: function(string, force){
  724. force = force || false;
  725. if(typeof string !== 'undefined')
  726. if(typeof string === 'string')
  727. this.title = string;
  728. else if(typeof string === 'function'){
  729. if(typeof string.promise === 'function')
  730. console.error('Promise was returned from title function, this is not supported.');
  731. var response = string();
  732. if(typeof response === 'string')
  733. this.title = response;
  734. else
  735. this.title = false;
  736. }else
  737. this.title = false;
  738. if(this.isAjaxLoading && !force)
  739. return;
  740. this.$title.html(this.title || '');
  741. this.updateTitleContainer();
  742. },
  743. setIcon: function(iconClass, force){
  744. force = force || false;
  745. if(typeof iconClass !== 'undefined')
  746. if(typeof iconClass === 'string')
  747. this.icon = iconClass;
  748. else if(typeof iconClass === 'function'){
  749. var response = iconClass();
  750. if(typeof response === 'string')
  751. this.icon = response;
  752. else
  753. this.icon = false;
  754. }
  755. else
  756. this.icon = false;
  757. if(this.isAjaxLoading && !force)
  758. return;
  759. this.$icon.html(this.icon ? '<i class="' + this.icon + '"></i>' : '');
  760. this.updateTitleContainer();
  761. },
  762. updateTitleContainer: function(){
  763. if(!this.title && !this.icon){
  764. this.$titleContainer.hide();
  765. }else{
  766. this.$titleContainer.show();
  767. }
  768. },
  769. setContentPrepend: function(content, force){
  770. if(!content)
  771. return;
  772. this.contentParsed.prepend(content);
  773. },
  774. setContentAppend: function(content){
  775. if(!content)
  776. return;
  777. this.contentParsed.append(content);
  778. },
  779. setContent: function(content, force){
  780. force = !!force;
  781. var that = this;
  782. if(content)
  783. this.contentParsed.html('').append(content);
  784. if(this.isAjaxLoading && !force)
  785. return;
  786. this.$content.html('');
  787. this.$content.append(this.contentParsed);
  788. setTimeout(function(){
  789. that.$body.find('input[autofocus]:visible:first').focus();
  790. }, 100);
  791. },
  792. loadingSpinner: false,
  793. showLoading: function(disableButtons){
  794. this.loadingSpinner = true;
  795. this.$jconfirmBox.addClass('loading');
  796. if(disableButtons)
  797. this.$btnc.find('button').prop('disabled', true);
  798. },
  799. hideLoading: function(enableButtons){
  800. this.loadingSpinner = false;
  801. this.$jconfirmBox.removeClass('loading');
  802. if(enableButtons)
  803. this.$btnc.find('button').prop('disabled', false);
  804. },
  805. ajaxResponse: false,
  806. contentParsed: '',
  807. isAjax: false,
  808. isAjaxLoading: false,
  809. _parseContent: function(){
  810. var that = this;
  811. var e = '&nbsp;';
  812. if(typeof this.content === 'function'){
  813. var res = this.content.apply(this);
  814. if(typeof res === 'string'){
  815. this.content = res;
  816. }
  817. else if(typeof res === 'object' && typeof res.always === 'function'){
  818. // this is ajax loading via promise
  819. this.isAjax = true;
  820. this.isAjaxLoading = true;
  821. res.always(function(data, status, xhr){
  822. that.ajaxResponse = {
  823. data: data,
  824. status: status,
  825. xhr: xhr
  826. };
  827. that._contentReady.resolve(data, status, xhr);
  828. if(typeof that.contentLoaded === 'function')
  829. that.contentLoaded(data, status, xhr);
  830. });
  831. this.content = e;
  832. }else{
  833. this.content = e;
  834. }
  835. }
  836. if(typeof this.content === 'string' && this.content.substr(0, 4).toLowerCase() === 'url:'){
  837. this.isAjax = true;
  838. this.isAjaxLoading = true;
  839. var u = this.content.substring(4, this.content.length);
  840. $.get(u).done(function(html){
  841. that.contentParsed.html(html);
  842. }).always(function(data, status, xhr){
  843. that.ajaxResponse = {
  844. data: data,
  845. status: status,
  846. xhr: xhr
  847. };
  848. that._contentReady.resolve(data, status, xhr);
  849. if(typeof that.contentLoaded === 'function')
  850. that.contentLoaded(data, status, xhr);
  851. });
  852. }
  853. if(!this.content)
  854. this.content = e;
  855. if(!this.isAjax){
  856. this.contentParsed.html(this.content);
  857. this.setContent();
  858. that._contentReady.resolve();
  859. }
  860. },
  861. _stopCountDown: function(){
  862. clearInterval(this.autoCloseInterval);
  863. if(this.$cd)
  864. this.$cd.remove();
  865. },
  866. _startCountDown: function(){
  867. var that = this;
  868. var opt = this.autoClose.split('|');
  869. if(opt.length !== 2){
  870. console.error('Invalid option for autoClose. example \'close|10000\'');
  871. return false;
  872. }
  873. var button_key = opt[0];
  874. var time = parseInt(opt[1]);
  875. if(typeof this.buttons[button_key] === 'undefined'){
  876. console.error('Invalid button key \'' + button_key + '\' for autoClose');
  877. return false;
  878. }
  879. var seconds = Math.ceil(time / 1000);
  880. this.$cd = $('<span class="countdown"> (' + seconds + ')</span>')
  881. .appendTo(this['$_' + button_key]);
  882. this.autoCloseInterval = setInterval(function(){
  883. that.$cd.html(' (' + (seconds -= 1) + ') ');
  884. if(seconds <= 0){
  885. that['$$' + button_key].trigger('click');
  886. that._stopCountDown();
  887. }
  888. }, 1000);
  889. },
  890. _getKey: function(key){
  891. // very necessary keys.
  892. switch(key){
  893. case 192:
  894. return 'tilde';
  895. case 13:
  896. return 'enter';
  897. case 16:
  898. return 'shift';
  899. case 9:
  900. return 'tab';
  901. case 20:
  902. return 'capslock';
  903. case 17:
  904. return 'ctrl';
  905. case 91:
  906. return 'win';
  907. case 18:
  908. return 'alt';
  909. case 27:
  910. return 'esc';
  911. case 32:
  912. return 'space';
  913. }
  914. // only trust alphabets with this.
  915. var initial = String.fromCharCode(key);
  916. if(/^[A-z0-9]+$/.test(initial))
  917. return initial.toLowerCase();
  918. else
  919. return false;
  920. },
  921. reactOnKey: function(e){
  922. var that = this;
  923. /*
  924. Prevent keyup event if the dialog is not last!
  925. */
  926. var a = $('.jconfirm');
  927. if(a.eq(a.length - 1)[0] !== this.$el[0])
  928. return false;
  929. var key = e.which;
  930. /*
  931. Do not react if Enter or Space is pressed on input elements
  932. */
  933. if(this.$content.find(':input').is(':focus') && /13|32/.test(key))
  934. return false;
  935. var keyChar = this._getKey(key);
  936. // If esc is pressed
  937. if(keyChar === 'esc' && this.escapeKey){
  938. if(this.escapeKey === true){
  939. this.$scrollPane.trigger('click');
  940. }
  941. else if(typeof this.escapeKey === 'string' || typeof this.escapeKey === 'function'){
  942. var buttonKey;
  943. if(typeof this.escapeKey === 'function'){
  944. buttonKey = this.escapeKey();
  945. }else{
  946. buttonKey = this.escapeKey;
  947. }
  948. if(buttonKey)
  949. if(typeof this.buttons[buttonKey] === 'undefined'){
  950. console.warn('Invalid escapeKey, no buttons found with key ' + buttonKey);
  951. }else{
  952. this['$_' + buttonKey].trigger('click');
  953. }
  954. }
  955. }
  956. // check if any button is listening to this key.
  957. $.each(this.buttons, function(key, button){
  958. if(button.keys.indexOf(keyChar) !== -1){
  959. that['$_' + key].trigger('click');
  960. }
  961. });
  962. },
  963. setDialogCenter: function(){
  964. console.info('setDialogCenter is deprecated, dialogs are centered with CSS3 tables');
  965. },
  966. _unwatchContent: function(){
  967. clearInterval(this._timer);
  968. },
  969. close: function(onClosePayload){
  970. var that = this;
  971. if(typeof this.onClose === 'function')
  972. this.onClose(onClosePayload);
  973. this._unwatchContent();
  974. /*
  975. unbind the window resize & keyup event.
  976. */
  977. $(window).unbind('resize.' + this._id);
  978. $(window).unbind('keyup.' + this._id);
  979. $(window).unbind('jcKeyDown.' + this._id);
  980. if(this.draggable){
  981. $(window).unbind('mousemove.' + this._id);
  982. $(window).unbind('mouseup.' + this._id);
  983. this.$titleContainer.unbind('mousedown');
  984. }
  985. that.$el.removeClass(that.loadedClass);
  986. $('body').removeClass('jconfirm-no-scroll-' + that._id);
  987. that.$jconfirmBoxContainer.removeClass('jconfirm-no-transition');
  988. setTimeout(function(){
  989. that.$body.addClass(that.closeAnimationParsed);
  990. that.$jconfirmBg.addClass('jconfirm-bg-h');
  991. var closeTimer = (that.closeAnimation === 'none') ? 1 : that.animationSpeed;
  992. setTimeout(function(){
  993. that.$el.remove();
  994. var l = w.jconfirm.instances;
  995. var i = w.jconfirm.instances.length - 1;
  996. for(i; i >= 0; i--){
  997. if(w.jconfirm.instances[i]._id === that._id){
  998. w.jconfirm.instances.splice(i, 1);
  999. }
  1000. }
  1001. // Focusing a element, scrolls automatically to that element.
  1002. // no instances should be open, lastFocused should be true, the lastFocused element must exists in DOM
  1003. if(!w.jconfirm.instances.length){
  1004. if(that.scrollToPreviousElement && w.jconfirm.lastFocused && w.jconfirm.lastFocused.length && $.contains(document, w.jconfirm.lastFocused[0])){
  1005. var $lf = w.jconfirm.lastFocused;
  1006. if(that.scrollToPreviousElementAnimate){
  1007. var st = $(window).scrollTop();
  1008. var ot = w.jconfirm.lastFocused.offset().top;
  1009. var wh = $(window).height();
  1010. if(!(ot > st && ot < (st + wh))){
  1011. var scrollTo = (ot - Math.round((wh / 3)));
  1012. $('html, body').animate({
  1013. scrollTop: scrollTo
  1014. }, that.animationSpeed, 'swing', function(){
  1015. // gracefully scroll and then focus.
  1016. $lf.focus();
  1017. });
  1018. }else{
  1019. // the element to be focused is already in view.
  1020. $lf.focus();
  1021. }
  1022. }else{
  1023. $lf.focus();
  1024. }
  1025. w.jconfirm.lastFocused = false;
  1026. }
  1027. }
  1028. if(typeof that.onDestroy === 'function')
  1029. that.onDestroy();
  1030. }, closeTimer * 0.40);
  1031. }, 50);
  1032. return true;
  1033. },
  1034. open: function(){
  1035. if(this.isOpen())
  1036. return false;
  1037. // var that = this;
  1038. this._buildHTML();
  1039. this._bindEvents();
  1040. this._open();
  1041. return true;
  1042. },
  1043. setStartingPoint: function(){
  1044. var el = false;
  1045. if(this.animateFromElement !== true && this.animateFromElement){
  1046. el = this.animateFromElement;
  1047. w.jconfirm.lastClicked = false;
  1048. }else if(w.jconfirm.lastClicked && this.animateFromElement === true){
  1049. el = w.jconfirm.lastClicked;
  1050. w.jconfirm.lastClicked = false;
  1051. }else{
  1052. return false;
  1053. }
  1054. if(!el)
  1055. return false;
  1056. var offset = el.offset();
  1057. var iTop = el.outerHeight() / 2;
  1058. var iLeft = el.outerWidth() / 2;
  1059. // placing position of jconfirm modal in center of clicked element
  1060. iTop -= this.$jconfirmBox.outerHeight() / 2;
  1061. iLeft -= this.$jconfirmBox.outerWidth() / 2;
  1062. // absolute position on screen
  1063. var sourceTop = offset.top + iTop;
  1064. sourceTop = sourceTop - this._scrollTop();
  1065. var sourceLeft = offset.left + iLeft;
  1066. // window halved
  1067. var wh = $(window).height() / 2;
  1068. var ww = $(window).width() / 2;
  1069. var targetH = wh - this.$jconfirmBox.outerHeight() / 2;
  1070. var targetW = ww - this.$jconfirmBox.outerWidth() / 2;
  1071. sourceTop -= targetH;
  1072. sourceLeft -= targetW;
  1073. // Check if the element is inside the viewable window.
  1074. if(Math.abs(sourceTop) > wh || Math.abs(sourceLeft) > ww)
  1075. return false;
  1076. this.$jconfirmBoxContainer.css('transform', 'translate(' + sourceLeft + 'px, ' + sourceTop + 'px)');
  1077. },
  1078. _open: function(){
  1079. var that = this;
  1080. if(typeof that.onOpenBefore === 'function')
  1081. that.onOpenBefore();
  1082. this.$body.removeClass(this.animationParsed);
  1083. this.$jconfirmBg.removeClass('jconfirm-bg-h');
  1084. this.$body.focus();
  1085. that.$jconfirmBoxContainer.css('transform', 'translate(' + 0 + 'px, ' + 0 + 'px)');
  1086. setTimeout(function(){
  1087. that.$body.css(that._getCSS(that.animationSpeed, 1));
  1088. that.$body.css({
  1089. 'transition-property': that.$body.css('transition-property') + ', margin'
  1090. });
  1091. that.$jconfirmBoxContainer.addClass('jconfirm-no-transition');
  1092. that._modalReady.resolve();
  1093. if(typeof that.onOpen === 'function')
  1094. that.onOpen();
  1095. that.$el.addClass(that.loadedClass);
  1096. }, this.animationSpeed);
  1097. },
  1098. loadedClass: 'jconfirm-open',
  1099. isClosed: function(){
  1100. return !this.$el || this.$el.parent().length === 0;
  1101. },
  1102. isOpen: function(){
  1103. return !this.isClosed();
  1104. },
  1105. toggle: function(){
  1106. if(!this.isOpen())
  1107. this.open();
  1108. else
  1109. this.close();
  1110. }
  1111. };
  1112. w.jconfirm.instances = [];
  1113. w.jconfirm.lastFocused = false;
  1114. w.jconfirm.pluginDefaults = {
  1115. template: '' +
  1116. '<div class="jconfirm">' +
  1117. '<div class="jconfirm-bg jconfirm-bg-h"></div>' +
  1118. '<div class="jconfirm-scrollpane">' +
  1119. '<div class="jconfirm-row">' +
  1120. '<div class="jconfirm-cell">' +
  1121. '<div class="jconfirm-holder">' +
  1122. '<div class="jc-bs3-container">' +
  1123. '<div class="jc-bs3-row">' +
  1124. '<div class="jconfirm-box-container jconfirm-animated">' +
  1125. '<div class="jconfirm-box" role="dialog" aria-labelledby="labelled" tabindex="-1">' +
  1126. '<div class="jconfirm-closeIcon">&times;</div>' +
  1127. '<div class="jconfirm-title-c">' +
  1128. '<span class="jconfirm-icon-c"></span>' +
  1129. '<span class="jconfirm-title"></span>' +
  1130. '</div>' +
  1131. '<div class="jconfirm-content-pane">' +
  1132. '<div class="jconfirm-content"></div>' +
  1133. '</div>' +
  1134. '<div class="jconfirm-buttons">' +
  1135. '</div>' +
  1136. '<div class="jconfirm-clear">' +
  1137. '</div>' +
  1138. '</div>' +
  1139. '</div>' +
  1140. '</div>' +
  1141. '</div>' +
  1142. '</div>' +
  1143. '</div>' +
  1144. '</div>' +
  1145. '</div></div>',
  1146. title: 'Hello',
  1147. titleClass: '',
  1148. type: 'default',
  1149. typeAnimated: true,
  1150. draggable: true,
  1151. dragWindowGap: 15,
  1152. dragWindowBorder: true,
  1153. animateFromElement: true,
  1154. /**
  1155. * @deprecated
  1156. */
  1157. alignMiddle: true,
  1158. smoothContent: true,
  1159. content: 'Are you sure to continue?',
  1160. buttons: {},
  1161. defaultButtons: {
  1162. ok: {
  1163. action: function(){
  1164. }
  1165. },
  1166. close: {
  1167. action: function(){
  1168. }
  1169. }
  1170. },
  1171. contentLoaded: function(){
  1172. },
  1173. icon: '',
  1174. lazyOpen: false,
  1175. bgOpacity: null,
  1176. theme: 'light',
  1177. animation: 'scale',
  1178. closeAnimation: 'scale',
  1179. animationSpeed: 400,
  1180. animationBounce: 1,
  1181. escapeKey: true,
  1182. rtl: false,
  1183. container: 'body',
  1184. containerFluid: false,
  1185. backgroundDismiss: false,
  1186. backgroundDismissAnimation: 'shake',
  1187. autoClose: false,
  1188. closeIcon: null,
  1189. closeIconClass: false,
  1190. watchInterval: 100,
  1191. columnClass: 'col-md-4 col-md-offset-4 col-sm-6 col-sm-offset-3 col-xs-10 col-xs-offset-1',
  1192. boxWidth: '50%',
  1193. scrollToPreviousElement: true,
  1194. scrollToPreviousElementAnimate: true,
  1195. useBootstrap: true,
  1196. offsetTop: 40,
  1197. offsetBottom: 40,
  1198. bootstrapClasses: {
  1199. container: 'container',
  1200. containerFluid: 'container-fluid',
  1201. row: 'row'
  1202. },
  1203. onContentReady: function(){
  1204. },
  1205. onOpenBefore: function(){
  1206. },
  1207. onOpen: function(){
  1208. },
  1209. onClose: function(){
  1210. },
  1211. onDestroy: function(){
  1212. },
  1213. onAction: function(){
  1214. }
  1215. };
  1216. /**
  1217. * This refers to the issue #241 and #246
  1218. *
  1219. * Problem:
  1220. * Button A is clicked (keydown) using the Keyboard ENTER key
  1221. * A opens the jconfirm modal B,
  1222. * B has registered ENTER key for one of its button C
  1223. * A is released (keyup), B gets the keyup event and triggers C.
  1224. *
  1225. * Solution:
  1226. * Register a global keydown event, that tells jconfirm if the keydown originated inside jconfirm
  1227. */
  1228. var keyDown = false;
  1229. $(window).on('keydown', function(e){
  1230. if(!keyDown){
  1231. var $target = $(e.target);
  1232. var pass = false;
  1233. if($target.closest('.jconfirm-box').length)
  1234. pass = true;
  1235. if(pass)
  1236. $(window).trigger('jcKeyDown');
  1237. keyDown = true;
  1238. }
  1239. });
  1240. $(window).on('keyup', function(){
  1241. keyDown = false;
  1242. });
  1243. w.jconfirm.lastClicked = false;
  1244. $(document).on('mousedown', 'button, a, [jc-source]', function(){
  1245. w.jconfirm.lastClicked = $(this);
  1246. });
  1247. }));