jquery-confirm.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. /*!
  2. * jquery-confirm v2.5.0 (http://craftpip.github.io/jquery-confirm/)
  3. * Author: Boniface Pereira
  4. * Website: www.craftpip.com
  5. * Contact: hey@craftpip.com
  6. *
  7. * Copyright 2013-2015 jquery-confirm
  8. * Licensed under MIT (https://github.com/craftpip/jquery-confirm/blob/master/LICENSE)
  9. */
  10. if (typeof jQuery === 'undefined') {
  11. throw new Error('jquery-confirm requires jQuery');
  12. }
  13. var jconfirm, Jconfirm;
  14. (function ($) {
  15. "use strict";
  16. $.fn.confirm = function (options, option2) {
  17. if (typeof options === 'undefined') options = {};
  18. if (typeof options === 'string')
  19. options = {
  20. content: options,
  21. title: (option2) ? option2 : false
  22. };
  23. /*
  24. * Alias of $.confirm to emulate native confirm()
  25. */
  26. $(this).each(function () {
  27. var $this = $(this);
  28. $this.on('click', function (e) {
  29. e.preventDefault();
  30. var jcOption = $.extend({}, options);
  31. if ($this.attr('data-title'))
  32. jcOption['title'] = $this.attr('data-title');
  33. if ($this.attr('data-content'))
  34. jcOption['content'] = $this.attr('data-content');
  35. jcOption['$target'] = $this;
  36. if ($this.attr('href') && !options['confirm'])
  37. jcOption['confirm'] = function () {
  38. location.href = $this.attr('href');
  39. };
  40. $.confirm(jcOption);
  41. });
  42. });
  43. return $(this);
  44. };
  45. $.confirm = function (options, option2) {
  46. if (typeof options === 'undefined') options = {};
  47. if (typeof options === 'string')
  48. options = {
  49. content: options,
  50. title: (option2) ? option2 : false
  51. };
  52. /*
  53. * Alias of jconfirm
  54. */
  55. return jconfirm(options);
  56. };
  57. $.alert = function (options, option2) {
  58. if (typeof options === 'undefined') options = {};
  59. if (typeof options === 'string')
  60. options = {
  61. content: options,
  62. title: (option2) ? option2 : false
  63. };
  64. /*
  65. * Alias of jconfirm
  66. */
  67. options.cancelButton = false;
  68. return jconfirm(options);
  69. };
  70. $.dialog = function (options, option2) {
  71. if (typeof options === 'undefined') options = {};
  72. if (typeof options === 'string')
  73. options = {
  74. content: options,
  75. title: (option2) ? option2 : false
  76. };
  77. /*
  78. * Alias of jconfirm
  79. */
  80. options.cancelButton = false;
  81. options.confirmButton = false;
  82. options.confirmKeys = [13];
  83. return jconfirm(options);
  84. };
  85. jconfirm = function (options) {
  86. if (typeof options === 'undefined') options = {};
  87. /*
  88. * initial function for calling.
  89. */
  90. if (jconfirm.defaults) {
  91. /*
  92. * Merge global defaults with plugin defaults
  93. */
  94. $.extend(jconfirm.pluginDefaults, jconfirm.defaults);
  95. }
  96. /*
  97. * merge options with plugin defaults.
  98. */
  99. var options = $.extend({}, jconfirm.pluginDefaults, options);
  100. return new Jconfirm(options);
  101. };
  102. Jconfirm = function (options) {
  103. /*
  104. * constructor function Jconfirm,
  105. * options = user options.
  106. */
  107. $.extend(this, options);
  108. this._init();
  109. };
  110. Jconfirm.prototype = {
  111. _init: function () {
  112. var that = this;
  113. this._rand = Math.round(Math.random() * 99999);
  114. this._buildHTML();
  115. this._bindEvents();
  116. setTimeout(function () {
  117. that.open();
  118. that._watchContent();
  119. }, 0);
  120. },
  121. _buildHTML: function () {
  122. var that = this;
  123. /*
  124. * Prefixing animations.
  125. */
  126. this.animation = 'anim-' + this.animation.toLowerCase();
  127. this.closeAnimation = 'anim-' + this.closeAnimation.toLowerCase();
  128. this.theme = 'jconfirm-' + this.theme.toLowerCase();
  129. if (this.animation == 'anim-none')
  130. this.animationSpeed = 0;
  131. this._lastFocused = $('body').find(':focus');
  132. /*
  133. * Append html.
  134. */
  135. this.$el = $(this.template).appendTo(this.container).addClass(this.theme);
  136. this.$el.find('.jconfirm-box-container').addClass(this.columnClass);
  137. this.$el.find('.jconfirm-bg').css(this._getCSS(this.animationSpeed, 1));
  138. this.$b = this.$el.find('.jconfirm-box').css(this._getCSS(this.animationSpeed, this.animationBounce)).addClass(this.animation);
  139. this.$body = this.$b; // alias
  140. /*
  141. * Add rtl class if rtl option has selected
  142. */
  143. if (this.rtl)
  144. this.$el.addClass("rtl");
  145. this._contentReady = $.Deferred();
  146. this._modalReady = $.Deferred();
  147. /*
  148. * Setup title contents
  149. */
  150. this.$title = this.$el.find('.title');
  151. this.contentDiv = this.$el.find('div.content');
  152. this.$content = this.contentDiv; // alias
  153. this.$contentPane = this.$el.find('.content-pane');
  154. this.$icon = this.$el.find('.icon-c');
  155. this.$closeIcon = this.$el.find('.closeIcon');
  156. this.$contentPane.css(this._getCSS(this.animationSpeed, 1));
  157. this.setTitle();
  158. this.setIcon();
  159. this._setButtons();
  160. if (this.closeIconClass)
  161. this.$closeIcon.html('<i class="' + this.closeIconClass + '"></i>');
  162. that._contentHash = this._hash(that.$content.html());
  163. $.when(this._contentReady, this._modalReady).then(function () {
  164. console.log('ready');
  165. that.setContent();
  166. that.setTitle();
  167. that.setIcon();
  168. });
  169. this._getContent();
  170. this._imagesLoaded();
  171. if (this.autoClose)
  172. this._startCountDown();
  173. },
  174. _unwatchContent: function () {
  175. clearInterval(this._timer);
  176. },
  177. _hash: function () {
  178. return btoa((encodeURIComponent(this.$content.html())));
  179. },
  180. _watchContent: function () {
  181. var that = this;
  182. this._timer = setInterval(function () {
  183. var now = that._hash(that.$content.html());
  184. if (that._contentHash != now) {
  185. that._contentHash = now;
  186. that.setDialogCenter();
  187. that._imagesLoaded();
  188. }
  189. }, this.watchInterval);
  190. },
  191. _bindEvents: function () {
  192. var that = this;
  193. var boxClicked = false;
  194. this.$el.find('.jconfirm-scrollpane').click(function (e) {
  195. // ignore propagated clicks
  196. if (!boxClicked) {
  197. // background clicked
  198. if (that.backgroundDismiss) {
  199. that.cancel();
  200. that.close();
  201. } else {
  202. that.$b.addClass('hilight');
  203. setTimeout(function () {
  204. that.$b.removeClass('hilight');
  205. }, 800);
  206. }
  207. }
  208. boxClicked = false;
  209. });
  210. this.$el.find('.jconfirm-box').click(function (e) {
  211. boxClicked = true;
  212. });
  213. if (this.$confirmButton) {
  214. this.$confirmButton.click(function (e) {
  215. e.preventDefault();
  216. var r = that.confirm(that.$b);
  217. that._stopCountDown();
  218. that.onAction('confirm');
  219. if (typeof r === 'undefined' || r)
  220. that.close();
  221. });
  222. }
  223. if (this.$cancelButton) {
  224. this.$cancelButton.click(function (e) {
  225. e.preventDefault();
  226. var r = that.cancel(that.$b);
  227. that._stopCountDown();
  228. that.onAction('cancel');
  229. if (typeof r === 'undefined' || r)
  230. that.close();
  231. });
  232. }
  233. if (this.$closeButton) {
  234. this.$closeButton.click(function (e) {
  235. e.preventDefault();
  236. that._stopCountDown();
  237. that.cancel();
  238. that.onAction('close');
  239. that.close();
  240. });
  241. }
  242. if (this.keyboardEnabled) {
  243. setTimeout(function () {
  244. $(window).on('keyup.' + this._rand, function (e) {
  245. that.reactOnKey(e);
  246. });
  247. }, 500);
  248. }
  249. $(window).on('resize.' + this._rand, function () {
  250. that.setDialogCenter(true);
  251. });
  252. },
  253. _getCSS: function (speed, bounce) {
  254. return {
  255. '-webkit-transition-duration': speed / 1000 + 's',
  256. 'transition-duration': speed / 1000 + 's',
  257. '-webkit-transition-timing-function': 'cubic-bezier(.36,1.1,.2, ' + bounce + ')',
  258. 'transition-timing-function': 'cubic-bezier(.36,1.1,.2, ' + bounce + ')'
  259. };
  260. },
  261. _imagesLoaded: function () {
  262. var that = this;
  263. $.each(this.$content.find('img:not(.loaded)'), function (i, a) {
  264. var interval = setInterval(function () {
  265. var h = $(a).css('height');
  266. console.log(h);
  267. if (h !== '0px') {
  268. $(a).addClass('loaded');
  269. that.setDialogCenter();
  270. clearInterval(interval);
  271. }
  272. }, 40);
  273. })
  274. },
  275. _setButtons: function () {
  276. /*
  277. * Settings up buttons
  278. */
  279. this.$btnc = this.$el.find('.buttons');
  280. if (this.confirmButton && $.trim(this.confirmButton) !== '') {
  281. this.$confirmButton = $('<button type="button" class="btn">' + this.confirmButton + '</button>').appendTo(this.$btnc).addClass(this.confirmButtonClass);
  282. }
  283. if (this.cancelButton && $.trim(this.cancelButton) !== '') {
  284. this.$cancelButton = $('<button type="button" class="btn">' + this.cancelButton + '</button>').appendTo(this.$btnc).addClass(this.cancelButtonClass);
  285. }
  286. if (!this.confirmButton && !this.cancelButton) {
  287. this.$btnc.hide();
  288. }
  289. if (!this.confirmButton && !this.cancelButton && this.closeIcon === null) {
  290. this.$closeButton = this.$b.find('.closeIcon').show();
  291. }
  292. if (this.closeIcon === true) {
  293. this.$closeButton = this.$b.find('.closeIcon').show();
  294. }
  295. },
  296. setTitle: function (string) {
  297. this.title = (typeof string !== 'undefined') ? string : this.title;
  298. this.$title.html(this.title || '');
  299. },
  300. setIcon: function (iconClass) {
  301. this.title = (typeof string !== 'undefined') ? iconClass : this.title;
  302. this.$icon.html(this.icon ? '<i class="' + this.icon + '"></i>' : '');
  303. },
  304. setContent: function (string) {
  305. // only set the content on the modal.
  306. var that = this;
  307. this.content = (typeof string == 'undefined') ? this.content : string;
  308. if (this.content == '') {
  309. this.$content.html(this.content);
  310. this.$contentPane.hide();
  311. } else {
  312. this.$content.html(this.content);
  313. this.$contentPane.show();
  314. }
  315. if (this.$content.hasClass('loading')) {
  316. this.$content.removeClass('loading');// it was loading via ajax.
  317. this.$btnc.find('button').prop('disabled', false);
  318. }
  319. },
  320. _getContent: function (string) {
  321. // get content from remote & stuff.
  322. var that = this;
  323. string = (string) ? string : this.content;
  324. this._isAjax = false;
  325. /*
  326. * Set content.
  327. */
  328. if (!this.content) { // if the content is falsy
  329. this.content = '';
  330. this.setContent(this.content);
  331. this._contentReady.reject();
  332. } else if (typeof this.content === 'string') {
  333. if (this.content.substr(0, 4).toLowerCase() === 'url:') {
  334. this._isAjax = true;
  335. this.$content.addClass('loading');
  336. this.$btnc.find('button').prop('disabled', true);
  337. var url = this.content.substring(4, this.content.length);
  338. $.get(url).done(function (html) {
  339. that.content = html;
  340. that._contentReady.resolve();
  341. }).always(function (data, status, xhr) {
  342. if (typeof that.contentLoaded === 'function')
  343. that.contentLoaded(data, status, xhr);
  344. });
  345. } else {
  346. this.setContent(this.content);
  347. this._contentReady.reject();
  348. }
  349. } else if (typeof this.content === 'function') {
  350. this.$content.addClass('loading');
  351. this.$btnc.find('button').attr('disabled', 'disabled');
  352. var promise = this.content(this);
  353. if (typeof promise !== 'object') {
  354. console.error('The content function must return jquery promise.');
  355. } else if (typeof promise.always !== 'function') {
  356. console.error('The object returned is not a jquery promise.');
  357. } else {
  358. this._isAjax = true;
  359. promise.always(function (data, status) {
  360. that._contentReady.resolve();
  361. });
  362. }
  363. } else {
  364. console.error('Invalid option for property content, passed: ' + typeof this.content);
  365. }
  366. this.setDialogCenter();
  367. },
  368. _stopCountDown: function () {
  369. clearInterval(this.timerInterval);
  370. if (this.$cd)
  371. this.$cd.remove();
  372. },
  373. _startCountDown: function () {
  374. var opt = this.autoClose.split('|');
  375. if (/cancel/.test(opt[0]) && this.type === 'alert') {
  376. return false;
  377. } else if (/confirm|cancel/.test(opt[0])) {
  378. this.$cd = $('<span class="countdown">').appendTo(this['$' + opt[0] + 'Button']);
  379. var that = this;
  380. that.$cd.parent().click();
  381. var time = opt[1] / 1000;
  382. this.timerInterval = setInterval(function () {
  383. that.$cd.html(' (' + (time -= 1) + ')');
  384. if (time === 0) {
  385. that.$cd.html('');
  386. that.$cd.parent().trigger('click');
  387. clearInterval(that.timerInterval);
  388. }
  389. }, 1000);
  390. } else {
  391. console.error('Invalid option ' + opt[0] + ', must be confirm/cancel');
  392. }
  393. },
  394. reactOnKey: function key(e) {
  395. /*
  396. * prevent keyup event if the dialog is not last!
  397. */
  398. var a = $('.jconfirm');
  399. if (a.eq(a.length - 1)[0] !== this.$el[0])
  400. return false;
  401. var key = e.which;
  402. // Do not react if Enter/Space is pressed on input elements
  403. if (this.contentDiv.find(':input').is(':focus') && /13|32/.test(key))
  404. return false;
  405. if ($.inArray(key, this.cancelKeys) !== -1) {
  406. /*
  407. * Cancel key pressed.
  408. */
  409. if (this.$cancelButton) {
  410. this.$cancelButton.click();
  411. } else {
  412. this.close();
  413. }
  414. }
  415. if ($.inArray(key, this.confirmKeys) !== -1) {
  416. /*
  417. * Confirm key pressed.
  418. */
  419. if (this.$confirmButton) {
  420. this.$confirmButton.click();
  421. }
  422. }
  423. },
  424. setDialogCenter: function () {
  425. console.log('setting dialog to center');
  426. if (this.$contentPane.css('display') == 'none') {
  427. var contentHeight = 0;
  428. var paneHeight = 0;
  429. } else {
  430. var contentHeight = this.$content.outerHeight();
  431. var paneHeight = this.$contentPane.height();
  432. if (paneHeight == 0)
  433. paneHeight = contentHeight;
  434. }
  435. var off = 100;
  436. var w = this.$content.outerWidth();
  437. //var s = '-clip-path: inset(0px 0px '+contentHeight+'px 0px);' +
  438. // 'clip-path: inset(0px 0px '+contentHeight+'px 0px)';
  439. this.$content.css({
  440. 'clip': 'rect(0px ' + (off + w) + 'px ' + contentHeight + 'px -' + off + 'px)'
  441. });
  442. this.$contentPane.css({
  443. 'height': contentHeight
  444. });
  445. var windowHeight = $(window).height();
  446. var boxHeight = this.$b.outerHeight() - paneHeight + contentHeight;
  447. var topMargin = (windowHeight - boxHeight) / 2;
  448. var minMargin = 100;
  449. if (boxHeight > (windowHeight - minMargin)) {
  450. var style = {
  451. 'margin-top': minMargin / 2,
  452. 'margin-bottom': minMargin / 2
  453. }
  454. } else {
  455. var style = {
  456. 'margin-top': topMargin
  457. }
  458. }
  459. this.$b.css(style);
  460. },
  461. close: function () {
  462. var that = this;
  463. if (this.isClosed())
  464. return false;
  465. if (typeof this.onClose === 'function')
  466. this.onClose();
  467. this._unwatchContent();
  468. that._lastFocused.focus();
  469. //this.observer.disconnect();
  470. /*
  471. unbind the window resize & keyup event.
  472. */
  473. $(window).unbind('resize.' + this._rand);
  474. if (this.keyboardEnabled)
  475. $(window).unbind('keyup.' + this._rand);
  476. that.$el.find('.jconfirm-bg').removeClass('seen');
  477. this.$b.addClass(this.closeAnimation);
  478. var closeTimer = (this.closeAnimation == 'anim-none') ? 0 : this.animationSpeed;
  479. setTimeout(function () {
  480. that.$el.remove();
  481. }, closeTimer * 25 / 100);
  482. jconfirm.record.closed += 1;
  483. jconfirm.record.currentlyOpen -= 1;
  484. return true;
  485. },
  486. open: function () {
  487. var that = this;
  488. if (this.isClosed())
  489. return false;
  490. that.$el.find('.jconfirm-bg').addClass('seen');
  491. this.$b.removeClass(this.animation);
  492. this.$b.find('input[autofocus]:visible:first').focus();
  493. jconfirm.record.opened += 1;
  494. jconfirm.record.currentlyOpen += 1;
  495. if (typeof this.onOpen === 'function')
  496. this.onOpen();
  497. var jcr = 'jconfirm-box' + this._rand;
  498. this.$b.attr('aria-labelledby', jcr).attr('tabindex', -1).focus();
  499. if (this.$title)
  500. this.$title.attr('id', jcr); else if (this.$content)
  501. this.$content.attr('id', jcr);
  502. setTimeout(function () {
  503. that.$b.css({
  504. 'transition-property': that.$b.css('transition-property') + ', margin'
  505. });
  506. that._modalReady.resolve();
  507. }, this.animationSpeed);
  508. return true;
  509. },
  510. isClosed: function () {
  511. return this.$el.css('display') === '';
  512. }
  513. };
  514. jconfirm.pluginDefaults = {
  515. template: '<div class="jconfirm"><div class="jconfirm-bg"></div><div class="jconfirm-scrollpane"><div class="container"><div class="row"><div class="jconfirm-box-container"><div class="jconfirm-box" role="dialog" aria-labelledby="labelled" tabindex="-1"><div class="closeIcon">&times;</div><div class="title-c"><span class="icon-c"></span><span class="title"></span></div><div class="content-pane"><div class="content"></div></div><div class="buttons"></div><div class="jquery-clear"></div></div></div></div></div></div></div>',
  516. title: 'Hello',
  517. content: 'Are you sure to continue?',
  518. contentLoaded: function () {
  519. },
  520. icon: '',
  521. confirmButton: 'Okay',
  522. cancelButton: 'Close',
  523. confirmButtonClass: 'btn-default',
  524. cancelButtonClass: 'btn-default',
  525. theme: 'white',
  526. animation: 'zoom',
  527. closeAnimation: 'scale',
  528. animationSpeed: 500,
  529. animationBounce: 1.2,
  530. keyboardEnabled: false,
  531. rtl: false,
  532. confirmKeys: [13], // ENTER key
  533. cancelKeys: [27], // ESC key
  534. container: 'body',
  535. confirm: function () {
  536. },
  537. cancel: function () {
  538. },
  539. backgroundDismiss: false,
  540. autoClose: false,
  541. closeIcon: null,
  542. closeIconClass: false,
  543. watchInterval: 100,
  544. columnClass: 'col-md-4 col-md-offset-4 col-sm-6 col-sm-offset-3 col-xs-10 col-xs-offset-1',
  545. onOpen: function () {
  546. },
  547. onClose: function () {
  548. },
  549. onAction: function () {
  550. }
  551. };
  552. jconfirm.record = {
  553. opened: 0,
  554. closed: 0,
  555. currentlyOpen: 0
  556. };
  557. })(jQuery);