├── .babelrc.js ├── .editorconfig ├── .eslintrc.json ├── .github ├── dependabot.yml.bak └── workflows │ └── main.yml ├── .gitignore ├── README.md ├── dist ├── bootstrap-confirmation.js └── bootstrap-confirmation.js.map ├── example └── index.html ├── package.json ├── rollup.config.js └── src ├── confirmation.js └── popover.js /.babelrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/env', 5 | { 6 | loose: true, 7 | exclude: ['transform-typeof-symbol'] 8 | } 9 | ] 10 | ], 11 | plugins: [ 12 | [ 13 | '@babel/proposal-object-rest-spread', 14 | { 15 | loose: true 16 | } 17 | ] 18 | ] 19 | }; 20 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = space 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb-base", 3 | "env": { 4 | "browser": true, 5 | "es6": true 6 | }, 7 | "rules": { 8 | "no-underscore-dangle": [ 9 | "off" 10 | ], 11 | "func-names": [ 12 | "off" 13 | ], 14 | "class-methods-use-this": [ 15 | "off" 16 | ], 17 | "max-len": [ 18 | "error", 19 | 120 20 | ], 21 | "brace-style": [ 22 | "error", 23 | "stroustrup" 24 | ], 25 | "no-param-reassign": [ 26 | "off" 27 | ], 28 | "key-spacing": [ 29 | "error", 30 | { 31 | "align": "colon" 32 | } 33 | ] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.github/dependabot.yml.bak: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "04:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: build 13 | run: | 14 | npm install 15 | npm run compile 16 | npm run test 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | bower_components 4 | node_modules 5 | yarn.lock 6 | package-lock.json 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bootstrap-Confirmation 2 | 3 | [![npm version](https://img.shields.io/npm/v/bootstrap-confirmation2.svg?style=flat-square)](https://www.npmjs.com/package/bootstrap-confirmation2) 4 | [![jsDelivr CDN](https://data.jsdelivr.com/v1/package/npm/bootstrap-confirmation2/badge)](https://www.jsdelivr.com/package/npm/bootstrap-confirmation2) 5 | [![GZIP size](https://img.shields.io/bundlephobia/minzip/bootstrap-confirmation2?label=gzip%20size)](https://bundlephobia.com/result?p=bootstrap-confirmation2) 6 | [![Build Status](https://github.com/mistic100/Bootstrap-Confirmation/workflows/CI/badge.svg)](https://github.com/mistic100/Bootstrap-Confirmation/actions) 7 | 8 | Bootstrap plugin for on-place confirm boxes using Popover. 9 | 10 | ## Documentation 11 | 12 | [bootstrap-confirmation.js.org](http://bootstrap-confirmation.js.org) 13 | 14 | ## Installation 15 | 16 | #### Bootstrap 4 17 | 18 | ``` 19 | npm install bootstrap-confirmation2 20 | ``` 21 | 22 | #### Bootstrap 3 23 | 24 | ``` 25 | npm install bootstrap-confirmation2@2.x.x 26 | ``` 27 | -------------------------------------------------------------------------------- /dist/bootstrap-confirmation.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Confirmation (v4.2.1) 3 | * @copyright 2013 Nimit Suwannagate 4 | * @copyright 2014-2021 Damien "Mistic" Sorel 5 | * @licence Apache License, Version 2.0 6 | */ 7 | (function (global, factory) { 8 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery'), require('bootstrap')) : 9 | typeof define === 'function' && define.amd ? define(['jquery', 'bootstrap'], factory) : 10 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.jQuery)); 11 | }(this, (function ($) { 'use strict'; 12 | 13 | function _defineProperties(target, props) { 14 | for (var i = 0; i < props.length; i++) { 15 | var descriptor = props[i]; 16 | descriptor.enumerable = descriptor.enumerable || false; 17 | descriptor.configurable = true; 18 | if ("value" in descriptor) descriptor.writable = true; 19 | Object.defineProperty(target, descriptor.key, descriptor); 20 | } 21 | } 22 | 23 | function _createClass(Constructor, protoProps, staticProps) { 24 | if (protoProps) _defineProperties(Constructor.prototype, protoProps); 25 | if (staticProps) _defineProperties(Constructor, staticProps); 26 | return Constructor; 27 | } 28 | 29 | function _extends() { 30 | _extends = Object.assign || function (target) { 31 | for (var i = 1; i < arguments.length; i++) { 32 | var source = arguments[i]; 33 | 34 | for (var key in source) { 35 | if (Object.prototype.hasOwnProperty.call(source, key)) { 36 | target[key] = source[key]; 37 | } 38 | } 39 | } 40 | 41 | return target; 42 | }; 43 | 44 | return _extends.apply(this, arguments); 45 | } 46 | 47 | function _inheritsLoose(subClass, superClass) { 48 | subClass.prototype = Object.create(superClass.prototype); 49 | subClass.prototype.constructor = subClass; 50 | 51 | _setPrototypeOf(subClass, superClass); 52 | } 53 | 54 | function _setPrototypeOf(o, p) { 55 | _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { 56 | o.__proto__ = p; 57 | return o; 58 | }; 59 | 60 | return _setPrototypeOf(o, p); 61 | } 62 | 63 | if (typeof $.fn.popover === 'undefined' || $.fn.popover.Constructor.VERSION.split('.').shift() !== '4') { 64 | throw new Error('Bootstrap Confirmation 4 requires Bootstrap Popover 4'); 65 | } 66 | 67 | var Popover = $.fn.popover.Constructor; 68 | 69 | /** 70 | * ------------------------------------------------------------------------ 71 | * Constants 72 | * ------------------------------------------------------------------------ 73 | */ 74 | 75 | var NAME = 'confirmation'; 76 | var VERSION = '4.2.1'; 77 | var DATA_KEY = "bs." + NAME; 78 | var EVENT_KEY = "." + DATA_KEY; 79 | var JQUERY_NO_CONFLICT = $.fn[NAME]; 80 | var BTN_CLASS_BASE = 'h-100 d-flex align-items-center'; 81 | var BTN_CLASS_DEFAULT = 'btn btn-sm'; 82 | 83 | var DefaultType = _extends({}, Popover.DefaultType, { 84 | singleton: 'boolean', 85 | popout: 'boolean', 86 | copyAttributes: '(string|array)', 87 | onConfirm: 'function', 88 | onCancel: 'function', 89 | btnOkClass: 'string', 90 | btnOkLabel: 'string', 91 | btnOkIconClass: 'string', 92 | btnOkIconContent: 'string', 93 | btnCancelClass: 'string', 94 | btnCancelLabel: 'string', 95 | btnCancelIconClass: 'string', 96 | btnCancelIconContent: 'string', 97 | buttons: 'array' 98 | }); 99 | 100 | var Default = _extends({}, Popover.Default, { 101 | _attributes: {}, 102 | _selector: null, 103 | placement: 'top', 104 | title: 'Are you sure?', 105 | trigger: 'click', 106 | confirmationEvent: undefined, 107 | content: '', 108 | singleton: false, 109 | popout: false, 110 | copyAttributes: 'href target', 111 | onConfirm: $.noop, 112 | onCancel: $.noop, 113 | btnOkClass: BTN_CLASS_DEFAULT + " btn-primary", 114 | btnOkLabel: 'Yes', 115 | btnOkIconClass: '', 116 | btnOkIconContent: '', 117 | btnCancelClass: BTN_CLASS_DEFAULT + " btn-secondary", 118 | btnCancelLabel: 'No', 119 | btnCancelIconClass: '', 120 | btnCancelIconContent: '', 121 | buttons: [], 122 | // @formatter:off 123 | template: "\n
\n
\n

\n
\n

\n
\n
\n
\n
\n
" // @formatter:on 124 | 125 | }); 126 | 127 | if (Default.whiteList) { 128 | Default.whiteList['*'].push('data-apply', 'data-dismiss'); 129 | } 130 | 131 | var ClassName = { 132 | FADE: 'fade', 133 | SHOW: 'show' 134 | }; 135 | var Selector = { 136 | TITLE: '.popover-header', 137 | CONTENT: '.confirmation-content', 138 | BUTTONS: '.confirmation-buttons .btn-group' 139 | }; 140 | var Keymap = { 141 | 13: 'Enter', 142 | 27: 'Escape', 143 | 39: 'ArrowRight', 144 | 40: 'ArrowDown' 145 | }; 146 | var Event = { 147 | HIDE: "hide" + EVENT_KEY, 148 | HIDDEN: "hidden" + EVENT_KEY, 149 | SHOW: "show" + EVENT_KEY, 150 | SHOWN: "shown" + EVENT_KEY, 151 | INSERTED: "inserted" + EVENT_KEY, 152 | CLICK: "click" + EVENT_KEY, 153 | FOCUSIN: "focusin" + EVENT_KEY, 154 | FOCUSOUT: "focusout" + EVENT_KEY, 155 | MOUSEENTER: "mouseenter" + EVENT_KEY, 156 | MOUSELEAVE: "mouseleave" + EVENT_KEY, 157 | CONFIRMED: "confirmed" + EVENT_KEY, 158 | CANCELED: "canceled" + EVENT_KEY, 159 | KEYUP: "keyup" + EVENT_KEY 160 | }; 161 | /** 162 | * ------------------------------------------------------------------------ 163 | * Class Definition 164 | * ------------------------------------------------------------------------ 165 | */ 166 | // keep track of the last openned confirmation for keyboard navigation 167 | 168 | var activeConfirmation; 169 | 170 | var Confirmation = /*#__PURE__*/function (_Popover) { 171 | _inheritsLoose(Confirmation, _Popover); 172 | 173 | // Constructor 174 | function Confirmation(element, config) { 175 | var _this; 176 | 177 | _this = _Popover.call(this, element, config) || this; 178 | 179 | if ((_this.config.popout || _this.config.singleton) && !_this.config.rootSelector) { 180 | throw new Error('The rootSelector option is required to use popout and singleton features since jQuery 3.'); 181 | } // keep trace of selectors 182 | 183 | 184 | _this._isDelegate = false; 185 | 186 | if (config.selector) { 187 | // container of buttons 188 | config._selector = config.rootSelector + " " + config.selector; 189 | _this.config._selector = config._selector; 190 | } else if (config._selector) { 191 | // children of container 192 | _this.config._selector = config._selector; 193 | _this._isDelegate = true; 194 | } else { 195 | // standalone 196 | _this.config._selector = config.rootSelector; 197 | } 198 | 199 | if (_this.config.confirmationEvent === undefined) { 200 | _this.config.confirmationEvent = _this.config.trigger; 201 | } 202 | 203 | if (!_this.config.selector) { 204 | _this._copyAttributes(); 205 | } 206 | 207 | _this._setConfirmationListeners(); 208 | 209 | return _this; 210 | } // Overrides 211 | 212 | 213 | var _proto = Confirmation.prototype; 214 | 215 | _proto.isWithContent = function isWithContent() { 216 | return true; 217 | }; 218 | 219 | _proto.setContent = function setContent() { 220 | var $tip = $(this.getTipElement()); 221 | 222 | var content = this._getContent(); 223 | 224 | if (typeof content === 'function') { 225 | content = content.call(this.element); 226 | } 227 | 228 | this.setElementContent($tip.find(Selector.TITLE), this.getTitle()); 229 | $tip.find(Selector.CONTENT).toggle(!!content); 230 | 231 | if (content) { 232 | this.setElementContent($tip.find(Selector.CONTENT), content); 233 | } 234 | 235 | if (this.config.buttons.length > 0) { 236 | this._setButtons($tip, this.config.buttons); 237 | } else { 238 | this._setStandardButtons($tip); 239 | } 240 | 241 | $tip.removeClass(ClassName.FADE + " " + ClassName.SHOW); 242 | 243 | this._setupKeyupEvent(); 244 | }; 245 | 246 | _proto.dispose = function dispose() { 247 | $('body').off(Event.CLICK + "." + this.uid); 248 | this.eventBody = false; 249 | 250 | this._cleanKeyupEvent(); 251 | 252 | _Popover.prototype.dispose.call(this); 253 | }; 254 | 255 | _proto.hide = function hide(callback) { 256 | this._cleanKeyupEvent(); 257 | 258 | _Popover.prototype.hide.call(this, callback); 259 | } // Private 260 | 261 | /** 262 | * Build configuration object 263 | * Bootstrap standard is to give priority to JS config over data attributes, 264 | * but for Confirmation we prefer data attributes 265 | * @param config 266 | * @return {*} 267 | * @private 268 | */ 269 | ; 270 | 271 | _proto._getConfig = function _getConfig(config) { 272 | config = _Popover.prototype._getConfig.call(this, config); 273 | var dataAttributes = $(this.element).data(); 274 | Object.keys(dataAttributes).forEach(function (dataAttr) { 275 | if (dataAttr.indexOf('btn') !== 0) { 276 | delete dataAttributes[dataAttr]; 277 | } 278 | }); 279 | return _extends({}, config, dataAttributes); 280 | } 281 | /** 282 | * Copy the value of `copyAttributes` on the config object 283 | * @private 284 | */ 285 | ; 286 | 287 | _proto._copyAttributes = function _copyAttributes() { 288 | var _this2 = this; 289 | 290 | this.config._attributes = {}; 291 | 292 | if (this.config.copyAttributes) { 293 | if (typeof this.config.copyAttributes === 'string') { 294 | this.config.copyAttributes = this.config.copyAttributes.split(' '); 295 | } 296 | } else { 297 | this.config.copyAttributes = []; 298 | } 299 | 300 | this.config.copyAttributes.forEach(function (attr) { 301 | _this2.config._attributes[attr] = $(_this2.element).attr(attr); 302 | }); 303 | } 304 | /** 305 | * Custom event listeners for popouts and singletons 306 | * @private 307 | */ 308 | ; 309 | 310 | _proto._setConfirmationListeners = function _setConfirmationListeners() { 311 | var self = this; 312 | 313 | if (!this.config.selector) { 314 | // cancel original event 315 | $(this.element).on(this.config.trigger, function (e, ack) { 316 | if (!ack) { 317 | e.preventDefault(); 318 | e.stopPropagation(); 319 | e.stopImmediatePropagation(); 320 | } 321 | }); // manage singleton 322 | 323 | $(this.element).on(Event.SHOWN, function () { 324 | if (self.config.singleton) { 325 | // close all other popover already initialized 326 | $(self.config._selector).not($(this)).filter(function () { 327 | return $(this).data(DATA_KEY) !== undefined; 328 | }).confirmation('hide'); 329 | } 330 | }); 331 | } else { 332 | // cancel original event 333 | $(this.element).on(this.config.trigger, this.config.selector, function (e, ack) { 334 | if (!ack) { 335 | e.preventDefault(); 336 | e.stopPropagation(); 337 | e.stopImmediatePropagation(); 338 | } 339 | }); 340 | } 341 | 342 | if (!this._isDelegate) { 343 | // manage popout 344 | this.eventBody = false; 345 | this.uid = this.element.id || Confirmation.getUID(NAME + "_group"); 346 | $(this.element).on(Event.SHOWN, function () { 347 | if (self.config.popout && !self.eventBody) { 348 | self.eventBody = $('body').on(Event.CLICK + "." + self.uid, function (e) { 349 | if ($(self.config._selector).is(e.target) || $(self.config._selector).has(e.target).length > 0) { 350 | return; 351 | } // close all popover already initialized 352 | 353 | 354 | $(self.config._selector).filter(function () { 355 | return $(this).data(DATA_KEY) !== undefined; 356 | }).confirmation('hide'); 357 | $('body').off(Event.CLICK + "." + self.uid); 358 | self.eventBody = false; 359 | }); 360 | } 361 | }); 362 | } 363 | } 364 | /** 365 | * Init the standard ok/cancel buttons 366 | * @param $tip 367 | * @private 368 | */ 369 | ; 370 | 371 | _proto._setStandardButtons = function _setStandardButtons($tip) { 372 | var buttons = [{ 373 | "class": this.config.btnOkClass, 374 | label: this.config.btnOkLabel, 375 | iconClass: this.config.btnOkIconClass, 376 | iconContent: this.config.btnOkIconContent, 377 | attr: this.config._attributes 378 | }, { 379 | "class": this.config.btnCancelClass, 380 | label: this.config.btnCancelLabel, 381 | iconClass: this.config.btnCancelIconClass, 382 | iconContent: this.config.btnCancelIconContent, 383 | cancel: true 384 | }]; 385 | 386 | this._setButtons($tip, buttons); 387 | } 388 | /** 389 | * Init the buttons 390 | * @param $tip 391 | * @param buttons 392 | * @private 393 | */ 394 | ; 395 | 396 | _proto._setButtons = function _setButtons($tip, buttons) { 397 | var self = this; 398 | var $group = $tip.find(Selector.BUTTONS).empty(); 399 | buttons.forEach(function (button) { 400 | var btn = $('').addClass(BTN_CLASS_BASE).addClass(button["class"] || BTN_CLASS_DEFAULT + " btn-secondary").html(button.label || '').attr(button.attr || (button.cancel ? {} : self.config._attributes)); 401 | 402 | if (button.iconClass || button.iconContent) { 403 | btn.prepend($('').addClass(button.iconClass || '').text(button.iconContent || '')); 404 | } 405 | 406 | btn.one('click', function (e) { 407 | if ($(this).attr('href') === '#') { 408 | e.preventDefault(); 409 | } 410 | 411 | if (button.onClick) { 412 | button.onClick.call($(self.element)); 413 | } 414 | 415 | if (button.cancel) { 416 | self.config.onCancel.call(self.element, button.value); 417 | $(self.element).trigger(Event.CANCELED, [button.value]); 418 | } else { 419 | self.config.onConfirm.call(self.element, button.value); 420 | $(self.element).trigger(Event.CONFIRMED, [button.value]); 421 | $(self.element).trigger(self.config.confirmationEvent, [true]); 422 | } 423 | 424 | self.hide(); 425 | }); 426 | $group.append(btn); 427 | }); 428 | } 429 | /** 430 | * Install the keyboatd event handler 431 | * @private 432 | */ 433 | ; 434 | 435 | _proto._setupKeyupEvent = function _setupKeyupEvent() { 436 | activeConfirmation = this; 437 | $(window).off(Event.KEYUP).on(Event.KEYUP, this._onKeyup.bind(this)); 438 | } 439 | /** 440 | * Remove the keyboard event handler 441 | * @private 442 | */ 443 | ; 444 | 445 | _proto._cleanKeyupEvent = function _cleanKeyupEvent() { 446 | if (activeConfirmation === this) { 447 | activeConfirmation = undefined; 448 | $(window).off(Event.KEYUP); 449 | } 450 | } 451 | /** 452 | * Event handler for keyboard navigation 453 | * @param event 454 | * @private 455 | */ 456 | ; 457 | 458 | _proto._onKeyup = function _onKeyup(event) { 459 | if (!this.tip) { 460 | this._cleanKeyupEvent(); 461 | 462 | return; 463 | } 464 | 465 | var $tip = $(this.getTipElement()); 466 | var key = event.key || Keymap[event.keyCode || event.which]; 467 | var $group = $tip.find(Selector.BUTTONS); 468 | var $active = $group.find('.active'); 469 | var $next; 470 | 471 | switch (key) { 472 | case 'Escape': 473 | this.hide(); 474 | break; 475 | 476 | case 'ArrowRight': 477 | if ($active.length && $active.next().length) { 478 | $next = $active.next(); 479 | } else { 480 | $next = $group.children().first(); 481 | } 482 | 483 | $active.removeClass('active'); 484 | $next.addClass('active').focus(); 485 | break; 486 | 487 | case 'ArrowLeft': 488 | if ($active.length && $active.prev().length) { 489 | $next = $active.prev(); 490 | } else { 491 | $next = $group.children().last(); 492 | } 493 | 494 | $active.removeClass('active'); 495 | $next.addClass('active').focus(); 496 | break; 497 | } 498 | } // Static 499 | 500 | /** 501 | * Generates an uui, copied from Bootrap's utils 502 | * @param {string} prefix 503 | * @returns {string} 504 | */ 505 | ; 506 | 507 | Confirmation.getUID = function getUID(prefix) { 508 | var uid = prefix; 509 | 510 | do { 511 | // eslint-disable-next-line no-bitwise 512 | uid += ~~(Math.random() * 1000000); // "~~" acts like a faster Math.floor() here 513 | } while (document.getElementById(uid)); 514 | 515 | return uid; 516 | }; 517 | 518 | Confirmation._jQueryInterface = function _jQueryInterface(config) { 519 | return this.each(function () { 520 | var data = $(this).data(DATA_KEY); 521 | 522 | var _config = typeof config === 'object' ? config : {}; 523 | 524 | _config.rootSelector = $(this).selector || _config.rootSelector; // this.selector removed in jQuery > 3 525 | 526 | if (!data && /destroy|hide/.test(config)) { 527 | return; 528 | } 529 | 530 | if (!data) { 531 | data = new Confirmation(this, _config); 532 | $(this).data(DATA_KEY, data); 533 | } 534 | 535 | if (typeof config === 'string') { 536 | if (typeof data[config] === 'undefined') { 537 | throw new TypeError("No method named \"" + config + "\""); 538 | } 539 | 540 | data[config](); 541 | } 542 | }); 543 | }; 544 | 545 | _createClass(Confirmation, null, [{ 546 | key: "VERSION", 547 | get: // Getters 548 | function get() { 549 | return VERSION; 550 | } 551 | }, { 552 | key: "Default", 553 | get: function get() { 554 | return Default; 555 | } 556 | }, { 557 | key: "NAME", 558 | get: function get() { 559 | return NAME; 560 | } 561 | }, { 562 | key: "DATA_KEY", 563 | get: function get() { 564 | return DATA_KEY; 565 | } 566 | }, { 567 | key: "Event", 568 | get: function get() { 569 | return Event; 570 | } 571 | }, { 572 | key: "EVENT_KEY", 573 | get: function get() { 574 | return EVENT_KEY; 575 | } 576 | }, { 577 | key: "DefaultType", 578 | get: function get() { 579 | return DefaultType; 580 | } 581 | }]); 582 | 583 | return Confirmation; 584 | }(Popover); 585 | /** 586 | * ------------------------------------------------------------------------ 587 | * jQuery 588 | * ------------------------------------------------------------------------ 589 | */ 590 | 591 | 592 | $.fn[NAME] = Confirmation._jQueryInterface; 593 | $.fn[NAME].Constructor = Confirmation; 594 | 595 | $.fn[NAME].noConflict = function () { 596 | $.fn[NAME] = JQUERY_NO_CONFLICT; 597 | return Confirmation._jQueryInterface; 598 | }; 599 | 600 | }))); 601 | //# sourceMappingURL=bootstrap-confirmation.js.map 602 | -------------------------------------------------------------------------------- /dist/bootstrap-confirmation.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"bootstrap-confirmation.js","sources":["../src/popover.js","../src/confirmation.js"],"sourcesContent":["import $ from 'jquery';\nimport 'bootstrap';\n\nif (typeof $.fn.popover === 'undefined' || $.fn.popover.Constructor.VERSION.split('.').shift() !== '4') {\n throw new Error('Bootstrap Confirmation 4 requires Bootstrap Popover 4');\n}\n\nconst Popover = $.fn.popover.Constructor;\n\nexport default Popover;\n","import $ from 'jquery';\nimport Popover from 'bootstrap/js/src/popover';\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'confirmation';\nconst VERSION = '$VERSION';\nconst DATA_KEY = `bs.${NAME}`;\nconst EVENT_KEY = `.${DATA_KEY}`;\nconst JQUERY_NO_CONFLICT = $.fn[NAME];\nconst BTN_CLASS_BASE = 'h-100 d-flex align-items-center';\nconst BTN_CLASS_DEFAULT = 'btn btn-sm';\n\nconst DefaultType = {\n ...Popover.DefaultType,\n singleton : 'boolean',\n popout : 'boolean',\n copyAttributes : '(string|array)',\n onConfirm : 'function',\n onCancel : 'function',\n btnOkClass : 'string',\n btnOkLabel : 'string',\n btnOkIconClass : 'string',\n btnOkIconContent : 'string',\n btnCancelClass : 'string',\n btnCancelLabel : 'string',\n btnCancelIconClass : 'string',\n btnCancelIconContent: 'string',\n buttons : 'array',\n};\n\nconst Default = {\n ...Popover.Default,\n _attributes : {},\n _selector : null,\n placement : 'top',\n title : 'Are you sure?',\n trigger : 'click',\n confirmationEvent : undefined,\n content : '',\n singleton : false,\n popout : false,\n copyAttributes : 'href target',\n onConfirm : $.noop,\n onCancel : $.noop,\n btnOkClass : `${BTN_CLASS_DEFAULT} btn-primary`,\n btnOkLabel : 'Yes',\n btnOkIconClass : '',\n btnOkIconContent : '',\n btnCancelClass : `${BTN_CLASS_DEFAULT} btn-secondary`,\n btnCancelLabel : 'No',\n btnCancelIconClass : '',\n btnCancelIconContent: '',\n buttons : [],\n // @formatter:off\n template : `\n
\n
\n

\n
\n

\n
\n
\n
\n
\n
`,\n // @formatter:on\n};\n\nif (Default.whiteList) {\n Default.whiteList['*'].push('data-apply', 'data-dismiss');\n}\n\nconst ClassName = {\n FADE: 'fade',\n SHOW: 'show',\n};\n\nconst Selector = {\n TITLE : '.popover-header',\n CONTENT: '.confirmation-content',\n BUTTONS: '.confirmation-buttons .btn-group',\n};\n\nconst Keymap = {\n 13: 'Enter',\n 27: 'Escape',\n 39: 'ArrowRight',\n 40: 'ArrowDown',\n};\n\nconst Event = {\n HIDE : `hide${EVENT_KEY}`,\n HIDDEN : `hidden${EVENT_KEY}`,\n SHOW : `show${EVENT_KEY}`,\n SHOWN : `shown${EVENT_KEY}`,\n INSERTED : `inserted${EVENT_KEY}`,\n CLICK : `click${EVENT_KEY}`,\n FOCUSIN : `focusin${EVENT_KEY}`,\n FOCUSOUT : `focusout${EVENT_KEY}`,\n MOUSEENTER: `mouseenter${EVENT_KEY}`,\n MOUSELEAVE: `mouseleave${EVENT_KEY}`,\n CONFIRMED : `confirmed${EVENT_KEY}`,\n CANCELED : `canceled${EVENT_KEY}`,\n KEYUP : `keyup${EVENT_KEY}`,\n};\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\n// keep track of the last openned confirmation for keyboard navigation\nlet activeConfirmation;\n\nclass Confirmation extends Popover {\n // Getters\n\n static get VERSION() {\n return VERSION;\n }\n\n static get Default() {\n return Default;\n }\n\n static get NAME() {\n return NAME;\n }\n\n static get DATA_KEY() {\n return DATA_KEY;\n }\n\n static get Event() {\n return Event;\n }\n\n static get EVENT_KEY() {\n return EVENT_KEY;\n }\n\n static get DefaultType() {\n return DefaultType;\n }\n\n // Constructor\n\n constructor(element, config) {\n super(element, config);\n\n if ((this.config.popout || this.config.singleton) && !this.config.rootSelector) {\n throw new Error('The rootSelector option is required to use popout and singleton features since jQuery 3.');\n }\n\n // keep trace of selectors\n this._isDelegate = false;\n\n if (config.selector) { // container of buttons\n config._selector = `${config.rootSelector} ${config.selector}`;\n this.config._selector = config._selector;\n }\n else if (config._selector) { // children of container\n this.config._selector = config._selector;\n this._isDelegate = true;\n }\n else { // standalone\n this.config._selector = config.rootSelector;\n }\n\n if (this.config.confirmationEvent === undefined) {\n this.config.confirmationEvent = this.config.trigger;\n }\n\n if (!this.config.selector) {\n this._copyAttributes();\n }\n\n this._setConfirmationListeners();\n }\n\n // Overrides\n\n isWithContent() {\n return true;\n }\n\n setContent() {\n const $tip = $(this.getTipElement());\n let content = this._getContent();\n\n if (typeof content === 'function') {\n content = content.call(this.element);\n }\n\n this.setElementContent($tip.find(Selector.TITLE), this.getTitle());\n\n $tip.find(Selector.CONTENT).toggle(!!content);\n if (content) {\n this.setElementContent($tip.find(Selector.CONTENT), content);\n }\n\n if (this.config.buttons.length > 0) {\n this._setButtons($tip, this.config.buttons);\n }\n else {\n this._setStandardButtons($tip);\n }\n\n $tip.removeClass(`${ClassName.FADE} ${ClassName.SHOW}`);\n\n this._setupKeyupEvent();\n }\n\n dispose() {\n $('body').off(`${Event.CLICK}.${this.uid}`);\n this.eventBody = false;\n this._cleanKeyupEvent();\n super.dispose();\n }\n\n hide(callback) {\n this._cleanKeyupEvent();\n super.hide(callback);\n }\n\n // Private\n\n /**\n * Build configuration object\n * Bootstrap standard is to give priority to JS config over data attributes,\n * but for Confirmation we prefer data attributes\n * @param config\n * @return {*}\n * @private\n */\n _getConfig(config) {\n config = super._getConfig(config);\n\n const dataAttributes = $(this.element).data();\n Object.keys(dataAttributes)\n .forEach((dataAttr) => {\n if (dataAttr.indexOf('btn') !== 0) {\n delete dataAttributes[dataAttr];\n }\n });\n\n return {\n ...config,\n ...dataAttributes,\n };\n }\n\n /**\n * Copy the value of `copyAttributes` on the config object\n * @private\n */\n _copyAttributes() {\n this.config._attributes = {};\n if (this.config.copyAttributes) {\n if (typeof this.config.copyAttributes === 'string') {\n this.config.copyAttributes = this.config.copyAttributes.split(' ');\n }\n }\n else {\n this.config.copyAttributes = [];\n }\n\n this.config.copyAttributes.forEach((attr) => {\n this.config._attributes[attr] = $(this.element).attr(attr);\n });\n }\n\n /**\n * Custom event listeners for popouts and singletons\n * @private\n */\n _setConfirmationListeners() {\n const self = this;\n\n if (!this.config.selector) {\n // cancel original event\n $(this.element).on(this.config.trigger, (e, ack) => {\n if (!ack) {\n e.preventDefault();\n e.stopPropagation();\n e.stopImmediatePropagation();\n }\n });\n\n // manage singleton\n $(this.element).on(Event.SHOWN, function () {\n if (self.config.singleton) {\n // close all other popover already initialized\n $(self.config._selector).not($(this)).filter(function () {\n return $(this).data(DATA_KEY) !== undefined;\n }).confirmation('hide');\n }\n });\n }\n else {\n // cancel original event\n $(this.element).on(this.config.trigger, this.config.selector, (e, ack) => {\n if (!ack) {\n e.preventDefault();\n e.stopPropagation();\n e.stopImmediatePropagation();\n }\n });\n }\n\n if (!this._isDelegate) {\n // manage popout\n this.eventBody = false;\n this.uid = this.element.id || Confirmation.getUID(`${NAME}_group`);\n\n $(this.element).on(Event.SHOWN, () => {\n if (self.config.popout && !self.eventBody) {\n self.eventBody = $('body').on(`${Event.CLICK}.${self.uid}`, (e) => {\n if ($(self.config._selector).is(e.target) || $(self.config._selector).has(e.target).length > 0) {\n return;\n }\n // close all popover already initialized\n $(self.config._selector).filter(function () {\n return $(this).data(DATA_KEY) !== undefined;\n }).confirmation('hide');\n\n $('body').off(`${Event.CLICK}.${self.uid}`);\n self.eventBody = false;\n });\n }\n });\n }\n }\n\n /**\n * Init the standard ok/cancel buttons\n * @param $tip\n * @private\n */\n _setStandardButtons($tip) {\n const buttons = [\n {\n class : this.config.btnOkClass,\n label : this.config.btnOkLabel,\n iconClass : this.config.btnOkIconClass,\n iconContent: this.config.btnOkIconContent,\n attr : this.config._attributes,\n },\n {\n class : this.config.btnCancelClass,\n label : this.config.btnCancelLabel,\n iconClass : this.config.btnCancelIconClass,\n iconContent: this.config.btnCancelIconContent,\n cancel : true,\n },\n ];\n\n this._setButtons($tip, buttons);\n }\n\n /**\n * Init the buttons\n * @param $tip\n * @param buttons\n * @private\n */\n _setButtons($tip, buttons) {\n const self = this;\n const $group = $tip.find(Selector.BUTTONS).empty();\n\n buttons.forEach((button) => {\n const btn = $('')\n .addClass(BTN_CLASS_BASE)\n .addClass(button.class || `${BTN_CLASS_DEFAULT} btn-secondary`)\n .html(button.label || '')\n .attr(button.attr || (button.cancel ? {} : self.config._attributes));\n\n if (button.iconClass || button.iconContent) {\n btn.prepend($('')\n .addClass(button.iconClass || '')\n .text(button.iconContent || ''));\n }\n\n btn.one('click', function (e) {\n if ($(this).attr('href') === '#') {\n e.preventDefault();\n }\n\n if (button.onClick) {\n button.onClick.call($(self.element));\n }\n\n if (button.cancel) {\n self.config.onCancel.call(self.element, button.value);\n $(self.element).trigger(Event.CANCELED, [button.value]);\n }\n else {\n self.config.onConfirm.call(self.element, button.value);\n $(self.element).trigger(Event.CONFIRMED, [button.value]);\n $(self.element).trigger(self.config.confirmationEvent, [true]);\n }\n\n self.hide();\n });\n\n $group.append(btn);\n });\n }\n\n /**\n * Install the keyboatd event handler\n * @private\n */\n _setupKeyupEvent() {\n activeConfirmation = this;\n $(window)\n .off(Event.KEYUP)\n .on(Event.KEYUP, this._onKeyup.bind(this));\n }\n\n /**\n * Remove the keyboard event handler\n * @private\n */\n _cleanKeyupEvent() {\n if (activeConfirmation === this) {\n activeConfirmation = undefined;\n $(window).off(Event.KEYUP);\n }\n }\n\n /**\n * Event handler for keyboard navigation\n * @param event\n * @private\n */\n _onKeyup(event) {\n if (!this.tip) {\n this._cleanKeyupEvent();\n return;\n }\n\n const $tip = $(this.getTipElement());\n const key = event.key || Keymap[event.keyCode || event.which];\n\n const $group = $tip.find(Selector.BUTTONS);\n const $active = $group.find('.active');\n let $next;\n\n switch (key) {\n case 'Escape':\n this.hide();\n break;\n\n case 'ArrowRight':\n if ($active.length && $active.next().length) {\n $next = $active.next();\n }\n else {\n $next = $group.children().first();\n }\n $active.removeClass('active');\n $next.addClass('active').focus();\n break;\n\n case 'ArrowLeft':\n if ($active.length && $active.prev().length) {\n $next = $active.prev();\n }\n else {\n $next = $group.children().last();\n }\n $active.removeClass('active');\n $next.addClass('active').focus();\n break;\n\n default:\n break;\n }\n }\n\n // Static\n\n /**\n * Generates an uui, copied from Bootrap's utils\n * @param {string} prefix\n * @returns {string}\n */\n static getUID(prefix) {\n let uid = prefix;\n do {\n // eslint-disable-next-line no-bitwise\n uid += ~~(Math.random() * 1000000); // \"~~\" acts like a faster Math.floor() here\n } while (document.getElementById(uid));\n return uid;\n }\n\n static _jQueryInterface(config) {\n return this.each(function () {\n let data = $(this).data(DATA_KEY);\n\n const _config = typeof config === 'object' ? config : {};\n _config.rootSelector = $(this).selector || _config.rootSelector; // this.selector removed in jQuery > 3\n\n if (!data && /destroy|hide/.test(config)) {\n return;\n }\n\n if (!data) {\n data = new Confirmation(this, _config);\n $(this).data(DATA_KEY, data);\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n }\n });\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n$.fn[NAME] = Confirmation._jQueryInterface;\n$.fn[NAME].Constructor = Confirmation;\n$.fn[NAME].noConflict = function () {\n $.fn[NAME] = JQUERY_NO_CONFLICT;\n return Confirmation._jQueryInterface;\n};\n\nexport default Confirmation;\n"],"names":["$","fn","popover","Constructor","VERSION","split","shift","Error","Popover","NAME","DATA_KEY","EVENT_KEY","JQUERY_NO_CONFLICT","BTN_CLASS_BASE","BTN_CLASS_DEFAULT","DefaultType","singleton","popout","copyAttributes","onConfirm","onCancel","btnOkClass","btnOkLabel","btnOkIconClass","btnOkIconContent","btnCancelClass","btnCancelLabel","btnCancelIconClass","btnCancelIconContent","buttons","Default","_attributes","_selector","placement","title","trigger","confirmationEvent","undefined","content","noop","template","whiteList","push","ClassName","FADE","SHOW","Selector","TITLE","CONTENT","BUTTONS","Keymap","Event","HIDE","HIDDEN","SHOWN","INSERTED","CLICK","FOCUSIN","FOCUSOUT","MOUSEENTER","MOUSELEAVE","CONFIRMED","CANCELED","KEYUP","activeConfirmation","Confirmation","element","config","rootSelector","_isDelegate","selector","_copyAttributes","_setConfirmationListeners","isWithContent","setContent","$tip","getTipElement","_getContent","call","setElementContent","find","getTitle","toggle","length","_setButtons","_setStandardButtons","removeClass","_setupKeyupEvent","dispose","off","uid","eventBody","_cleanKeyupEvent","hide","callback","_getConfig","dataAttributes","data","Object","keys","forEach","dataAttr","indexOf","attr","self","on","e","ack","preventDefault","stopPropagation","stopImmediatePropagation","not","filter","confirmation","id","getUID","is","target","has","label","iconClass","iconContent","cancel","$group","empty","button","btn","addClass","html","prepend","text","one","onClick","value","append","window","_onKeyup","bind","event","tip","key","keyCode","which","$active","$next","next","children","first","focus","prev","last","prefix","Math","random","document","getElementById","_jQueryInterface","each","_config","test","TypeError","noConflict"],"mappings":"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"} -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Bootstrap Confirmation 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 | 21 |
22 |
23 | 29 | 30 |
31 |
Basic
32 |
33 | 34 |
35 |
36 | 37 |
38 |
Link
39 |
40 | Go to Google 42 |
43 |
44 | 45 |
46 |
Customize
47 |
48 | 56 |
57 |
58 | 59 |
60 |
Directions
61 |
62 | 63 | 64 | 65 | 66 |
67 |
68 | 69 |
70 |
Singleton
71 |
72 | 73 | 74 |
75 |
76 | 77 |
78 |
Popout
79 |
80 | 81 | 82 |
83 |
84 | 85 |
86 |
Delegation
87 |
88 | 89 | 90 |
91 |
92 | 93 |
94 |
Custom event
95 |
96 | 101 |
102 |
103 | 104 |
105 |
Custom buttons
106 |
107 | 108 | 109 |
110 |
111 | 112 |
113 |
Override data attributes
114 |
115 | 116 | 120 |
121 |
122 |
123 |
124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 236 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap-confirmation2", 3 | "version": "4.2.1", 4 | "homepage": "https://bootstrap-confirmation.js.org", 5 | "description": "Bootstrap plugin for on-place confirm boxes using Popover", 6 | "license": "Apache-2.0", 7 | "authors": [ 8 | { 9 | "name": "Nimit Suwannagate", 10 | "email": "ethaizone@hotmail.com" 11 | }, 12 | { 13 | "name": "Damien \"Mistic\" Sorel", 14 | "email": "contact@git.strangeplanet.fr", 15 | "homepage": "https://www.strangeplanet.fr" 16 | } 17 | ], 18 | "main": "dist/bootstrap-confirmation.js", 19 | "files": [ 20 | "dist/", 21 | "src/confirmation.js" 22 | ], 23 | "keywords": [ 24 | "bootstrap", 25 | "confirmation", 26 | "popup" 27 | ], 28 | "peerDependencies": { 29 | "bootstrap": "^4.0.0", 30 | "jquery": "1.9.1 - 3", 31 | "popper.js": "^1.16.1" 32 | }, 33 | "devDependencies": { 34 | "@babel/core": "^7.5.0", 35 | "@babel/plugin-proposal-object-rest-spread": "^7.5.1", 36 | "@babel/preset-env": "^7.5.0", 37 | "babel-eslint": "^10.0.1", 38 | "bootstrap": "^4.2.1", 39 | "eslint": "^8.0.1", 40 | "eslint-config-airbnb-base": "^14.0.0", 41 | "eslint-plugin-import": "^2.10.0", 42 | "jquery": "^3.3.1", 43 | "live-server": "^1.2.0", 44 | "nodemon": "^2.0.0", 45 | "npm-run-all": "^4.1.2", 46 | "popper.js": "^1.12.9", 47 | "rollup": "^2.0.2", 48 | "rollup-plugin-babel": "^4.2.0", 49 | "rollup-plugin-replace": "^2.0.0" 50 | }, 51 | "repository": { 52 | "type": "git", 53 | "url": "git://github.com/mistic100/Bootstrap-Confirmation.git" 54 | }, 55 | "bugs": { 56 | "url": "https://github.com/mistic100/Bootstrap-Confirmation/issues" 57 | }, 58 | "scripts": { 59 | "compile": "rollup --config rollup.config.js --file dist/bootstrap-confirmation.js src/confirmation.js", 60 | "lint": "eslint src", 61 | "server": "live-server --watch=dist,example --open=example", 62 | "start": "npm run compile && npm-run-all --parallel watch server", 63 | "test": "npm run lint", 64 | "watch": "nodemon --watch src --ext js --exec \"npm run compile\"" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import replace from 'rollup-plugin-replace'; 3 | 4 | const pkg = require('./package.json'); 5 | 6 | export default { 7 | output : { 8 | format : 'umd', 9 | name : 'bootstrap-confirmation', 10 | sourcemap: true, 11 | interop : false, 12 | exports : 'none', 13 | globals : { 14 | 'jquery': 'jQuery' 15 | }, 16 | banner : `/*! 17 | * Bootstrap Confirmation (v${pkg.version}) 18 | * @copyright 2013 Nimit Suwannagate 19 | * @copyright 2014-${(new Date()).getFullYear()} Damien "Mistic" Sorel 20 | * @licence Apache License, Version 2.0 21 | */` 22 | }, 23 | external: [ 24 | 'jquery', 25 | 'bootstrap' 26 | ], 27 | plugins : [ 28 | replace({ 29 | delimiters: ['', ''], 30 | 31 | '$VERSION' : pkg.version, 32 | 'import Popover from \'bootstrap/js/src/popover\';': 'import Popover from \'./popover\';', 33 | 'export default Confirmation;' : '' 34 | }), 35 | babel({ 36 | exclude: 'node_modules/**' 37 | }) 38 | ] 39 | }; 40 | -------------------------------------------------------------------------------- /src/confirmation.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | import Popover from 'bootstrap/js/src/popover'; 3 | 4 | /** 5 | * ------------------------------------------------------------------------ 6 | * Constants 7 | * ------------------------------------------------------------------------ 8 | */ 9 | 10 | const NAME = 'confirmation'; 11 | const VERSION = '$VERSION'; 12 | const DATA_KEY = `bs.${NAME}`; 13 | const EVENT_KEY = `.${DATA_KEY}`; 14 | const JQUERY_NO_CONFLICT = $.fn[NAME]; 15 | const BTN_CLASS_BASE = 'h-100 d-flex align-items-center'; 16 | const BTN_CLASS_DEFAULT = 'btn btn-sm'; 17 | 18 | const DefaultType = { 19 | ...Popover.DefaultType, 20 | singleton : 'boolean', 21 | popout : 'boolean', 22 | copyAttributes : '(string|array)', 23 | onConfirm : 'function', 24 | onCancel : 'function', 25 | btnOkClass : 'string', 26 | btnOkLabel : 'string', 27 | btnOkIconClass : 'string', 28 | btnOkIconContent : 'string', 29 | btnCancelClass : 'string', 30 | btnCancelLabel : 'string', 31 | btnCancelIconClass : 'string', 32 | btnCancelIconContent: 'string', 33 | buttons : 'array', 34 | }; 35 | 36 | const Default = { 37 | ...Popover.Default, 38 | _attributes : {}, 39 | _selector : null, 40 | placement : 'top', 41 | title : 'Are you sure?', 42 | trigger : 'click', 43 | confirmationEvent : undefined, 44 | content : '', 45 | singleton : false, 46 | popout : false, 47 | copyAttributes : 'href target', 48 | onConfirm : $.noop, 49 | onCancel : $.noop, 50 | btnOkClass : `${BTN_CLASS_DEFAULT} btn-primary`, 51 | btnOkLabel : 'Yes', 52 | btnOkIconClass : '', 53 | btnOkIconContent : '', 54 | btnCancelClass : `${BTN_CLASS_DEFAULT} btn-secondary`, 55 | btnCancelLabel : 'No', 56 | btnCancelIconClass : '', 57 | btnCancelIconContent: '', 58 | buttons : [], 59 | // @formatter:off 60 | template : ` 61 |
62 |
63 |

64 |
65 |

66 |
67 |
68 |
69 |
70 |
`, 71 | // @formatter:on 72 | }; 73 | 74 | if (Default.whiteList) { 75 | Default.whiteList['*'].push('data-apply', 'data-dismiss'); 76 | } 77 | 78 | const ClassName = { 79 | FADE: 'fade', 80 | SHOW: 'show', 81 | }; 82 | 83 | const Selector = { 84 | TITLE : '.popover-header', 85 | CONTENT: '.confirmation-content', 86 | BUTTONS: '.confirmation-buttons .btn-group', 87 | }; 88 | 89 | const Keymap = { 90 | 13: 'Enter', 91 | 27: 'Escape', 92 | 39: 'ArrowRight', 93 | 40: 'ArrowDown', 94 | }; 95 | 96 | const Event = { 97 | HIDE : `hide${EVENT_KEY}`, 98 | HIDDEN : `hidden${EVENT_KEY}`, 99 | SHOW : `show${EVENT_KEY}`, 100 | SHOWN : `shown${EVENT_KEY}`, 101 | INSERTED : `inserted${EVENT_KEY}`, 102 | CLICK : `click${EVENT_KEY}`, 103 | FOCUSIN : `focusin${EVENT_KEY}`, 104 | FOCUSOUT : `focusout${EVENT_KEY}`, 105 | MOUSEENTER: `mouseenter${EVENT_KEY}`, 106 | MOUSELEAVE: `mouseleave${EVENT_KEY}`, 107 | CONFIRMED : `confirmed${EVENT_KEY}`, 108 | CANCELED : `canceled${EVENT_KEY}`, 109 | KEYUP : `keyup${EVENT_KEY}`, 110 | }; 111 | 112 | /** 113 | * ------------------------------------------------------------------------ 114 | * Class Definition 115 | * ------------------------------------------------------------------------ 116 | */ 117 | 118 | // keep track of the last openned confirmation for keyboard navigation 119 | let activeConfirmation; 120 | 121 | class Confirmation extends Popover { 122 | // Getters 123 | 124 | static get VERSION() { 125 | return VERSION; 126 | } 127 | 128 | static get Default() { 129 | return Default; 130 | } 131 | 132 | static get NAME() { 133 | return NAME; 134 | } 135 | 136 | static get DATA_KEY() { 137 | return DATA_KEY; 138 | } 139 | 140 | static get Event() { 141 | return Event; 142 | } 143 | 144 | static get EVENT_KEY() { 145 | return EVENT_KEY; 146 | } 147 | 148 | static get DefaultType() { 149 | return DefaultType; 150 | } 151 | 152 | // Constructor 153 | 154 | constructor(element, config) { 155 | super(element, config); 156 | 157 | if ((this.config.popout || this.config.singleton) && !this.config.rootSelector) { 158 | throw new Error('The rootSelector option is required to use popout and singleton features since jQuery 3.'); 159 | } 160 | 161 | // keep trace of selectors 162 | this._isDelegate = false; 163 | 164 | if (config.selector) { // container of buttons 165 | config._selector = `${config.rootSelector} ${config.selector}`; 166 | this.config._selector = config._selector; 167 | } 168 | else if (config._selector) { // children of container 169 | this.config._selector = config._selector; 170 | this._isDelegate = true; 171 | } 172 | else { // standalone 173 | this.config._selector = config.rootSelector; 174 | } 175 | 176 | if (this.config.confirmationEvent === undefined) { 177 | this.config.confirmationEvent = this.config.trigger; 178 | } 179 | 180 | if (!this.config.selector) { 181 | this._copyAttributes(); 182 | } 183 | 184 | this._setConfirmationListeners(); 185 | } 186 | 187 | // Overrides 188 | 189 | isWithContent() { 190 | return true; 191 | } 192 | 193 | setContent() { 194 | const $tip = $(this.getTipElement()); 195 | let content = this._getContent(); 196 | 197 | if (typeof content === 'function') { 198 | content = content.call(this.element); 199 | } 200 | 201 | this.setElementContent($tip.find(Selector.TITLE), this.getTitle()); 202 | 203 | $tip.find(Selector.CONTENT).toggle(!!content); 204 | if (content) { 205 | this.setElementContent($tip.find(Selector.CONTENT), content); 206 | } 207 | 208 | if (this.config.buttons.length > 0) { 209 | this._setButtons($tip, this.config.buttons); 210 | } 211 | else { 212 | this._setStandardButtons($tip); 213 | } 214 | 215 | $tip.removeClass(`${ClassName.FADE} ${ClassName.SHOW}`); 216 | 217 | this._setupKeyupEvent(); 218 | } 219 | 220 | dispose() { 221 | $('body').off(`${Event.CLICK}.${this.uid}`); 222 | this.eventBody = false; 223 | this._cleanKeyupEvent(); 224 | super.dispose(); 225 | } 226 | 227 | hide(callback) { 228 | this._cleanKeyupEvent(); 229 | super.hide(callback); 230 | } 231 | 232 | // Private 233 | 234 | /** 235 | * Build configuration object 236 | * Bootstrap standard is to give priority to JS config over data attributes, 237 | * but for Confirmation we prefer data attributes 238 | * @param config 239 | * @return {*} 240 | * @private 241 | */ 242 | _getConfig(config) { 243 | config = super._getConfig(config); 244 | 245 | const dataAttributes = $(this.element).data(); 246 | Object.keys(dataAttributes) 247 | .forEach((dataAttr) => { 248 | if (dataAttr.indexOf('btn') !== 0) { 249 | delete dataAttributes[dataAttr]; 250 | } 251 | }); 252 | 253 | return { 254 | ...config, 255 | ...dataAttributes, 256 | }; 257 | } 258 | 259 | /** 260 | * Copy the value of `copyAttributes` on the config object 261 | * @private 262 | */ 263 | _copyAttributes() { 264 | this.config._attributes = {}; 265 | if (this.config.copyAttributes) { 266 | if (typeof this.config.copyAttributes === 'string') { 267 | this.config.copyAttributes = this.config.copyAttributes.split(' '); 268 | } 269 | } 270 | else { 271 | this.config.copyAttributes = []; 272 | } 273 | 274 | this.config.copyAttributes.forEach((attr) => { 275 | this.config._attributes[attr] = $(this.element).attr(attr); 276 | }); 277 | } 278 | 279 | /** 280 | * Custom event listeners for popouts and singletons 281 | * @private 282 | */ 283 | _setConfirmationListeners() { 284 | const self = this; 285 | 286 | if (!this.config.selector) { 287 | // cancel original event 288 | $(this.element).on(this.config.trigger, (e, ack) => { 289 | if (!ack) { 290 | e.preventDefault(); 291 | e.stopPropagation(); 292 | e.stopImmediatePropagation(); 293 | } 294 | }); 295 | 296 | // manage singleton 297 | $(this.element).on(Event.SHOWN, function () { 298 | if (self.config.singleton) { 299 | // close all other popover already initialized 300 | $(self.config._selector).not($(this)).filter(function () { 301 | return $(this).data(DATA_KEY) !== undefined; 302 | }).confirmation('hide'); 303 | } 304 | }); 305 | } 306 | else { 307 | // cancel original event 308 | $(this.element).on(this.config.trigger, this.config.selector, (e, ack) => { 309 | if (!ack) { 310 | e.preventDefault(); 311 | e.stopPropagation(); 312 | e.stopImmediatePropagation(); 313 | } 314 | }); 315 | } 316 | 317 | if (!this._isDelegate) { 318 | // manage popout 319 | this.eventBody = false; 320 | this.uid = this.element.id || Confirmation.getUID(`${NAME}_group`); 321 | 322 | $(this.element).on(Event.SHOWN, () => { 323 | if (self.config.popout && !self.eventBody) { 324 | self.eventBody = $('body').on(`${Event.CLICK}.${self.uid}`, (e) => { 325 | if ($(self.config._selector).is(e.target) || $(self.config._selector).has(e.target).length > 0) { 326 | return; 327 | } 328 | // close all popover already initialized 329 | $(self.config._selector).filter(function () { 330 | return $(this).data(DATA_KEY) !== undefined; 331 | }).confirmation('hide'); 332 | 333 | $('body').off(`${Event.CLICK}.${self.uid}`); 334 | self.eventBody = false; 335 | }); 336 | } 337 | }); 338 | } 339 | } 340 | 341 | /** 342 | * Init the standard ok/cancel buttons 343 | * @param $tip 344 | * @private 345 | */ 346 | _setStandardButtons($tip) { 347 | const buttons = [ 348 | { 349 | class : this.config.btnOkClass, 350 | label : this.config.btnOkLabel, 351 | iconClass : this.config.btnOkIconClass, 352 | iconContent: this.config.btnOkIconContent, 353 | attr : this.config._attributes, 354 | }, 355 | { 356 | class : this.config.btnCancelClass, 357 | label : this.config.btnCancelLabel, 358 | iconClass : this.config.btnCancelIconClass, 359 | iconContent: this.config.btnCancelIconContent, 360 | cancel : true, 361 | }, 362 | ]; 363 | 364 | this._setButtons($tip, buttons); 365 | } 366 | 367 | /** 368 | * Init the buttons 369 | * @param $tip 370 | * @param buttons 371 | * @private 372 | */ 373 | _setButtons($tip, buttons) { 374 | const self = this; 375 | const $group = $tip.find(Selector.BUTTONS).empty(); 376 | 377 | buttons.forEach((button) => { 378 | const btn = $('') 379 | .addClass(BTN_CLASS_BASE) 380 | .addClass(button.class || `${BTN_CLASS_DEFAULT} btn-secondary`) 381 | .html(button.label || '') 382 | .attr(button.attr || (button.cancel ? {} : self.config._attributes)); 383 | 384 | if (button.iconClass || button.iconContent) { 385 | btn.prepend($('') 386 | .addClass(button.iconClass || '') 387 | .text(button.iconContent || '')); 388 | } 389 | 390 | btn.one('click', function (e) { 391 | if ($(this).attr('href') === '#') { 392 | e.preventDefault(); 393 | } 394 | 395 | if (button.onClick) { 396 | button.onClick.call($(self.element)); 397 | } 398 | 399 | if (button.cancel) { 400 | self.config.onCancel.call(self.element, button.value); 401 | $(self.element).trigger(Event.CANCELED, [button.value]); 402 | } 403 | else { 404 | self.config.onConfirm.call(self.element, button.value); 405 | $(self.element).trigger(Event.CONFIRMED, [button.value]); 406 | $(self.element).trigger(self.config.confirmationEvent, [true]); 407 | } 408 | 409 | self.hide(); 410 | }); 411 | 412 | $group.append(btn); 413 | }); 414 | } 415 | 416 | /** 417 | * Install the keyboatd event handler 418 | * @private 419 | */ 420 | _setupKeyupEvent() { 421 | activeConfirmation = this; 422 | $(window) 423 | .off(Event.KEYUP) 424 | .on(Event.KEYUP, this._onKeyup.bind(this)); 425 | } 426 | 427 | /** 428 | * Remove the keyboard event handler 429 | * @private 430 | */ 431 | _cleanKeyupEvent() { 432 | if (activeConfirmation === this) { 433 | activeConfirmation = undefined; 434 | $(window).off(Event.KEYUP); 435 | } 436 | } 437 | 438 | /** 439 | * Event handler for keyboard navigation 440 | * @param event 441 | * @private 442 | */ 443 | _onKeyup(event) { 444 | if (!this.tip) { 445 | this._cleanKeyupEvent(); 446 | return; 447 | } 448 | 449 | const $tip = $(this.getTipElement()); 450 | const key = event.key || Keymap[event.keyCode || event.which]; 451 | 452 | const $group = $tip.find(Selector.BUTTONS); 453 | const $active = $group.find('.active'); 454 | let $next; 455 | 456 | switch (key) { 457 | case 'Escape': 458 | this.hide(); 459 | break; 460 | 461 | case 'ArrowRight': 462 | if ($active.length && $active.next().length) { 463 | $next = $active.next(); 464 | } 465 | else { 466 | $next = $group.children().first(); 467 | } 468 | $active.removeClass('active'); 469 | $next.addClass('active').focus(); 470 | break; 471 | 472 | case 'ArrowLeft': 473 | if ($active.length && $active.prev().length) { 474 | $next = $active.prev(); 475 | } 476 | else { 477 | $next = $group.children().last(); 478 | } 479 | $active.removeClass('active'); 480 | $next.addClass('active').focus(); 481 | break; 482 | 483 | default: 484 | break; 485 | } 486 | } 487 | 488 | // Static 489 | 490 | /** 491 | * Generates an uui, copied from Bootrap's utils 492 | * @param {string} prefix 493 | * @returns {string} 494 | */ 495 | static getUID(prefix) { 496 | let uid = prefix; 497 | do { 498 | // eslint-disable-next-line no-bitwise 499 | uid += ~~(Math.random() * 1000000); // "~~" acts like a faster Math.floor() here 500 | } while (document.getElementById(uid)); 501 | return uid; 502 | } 503 | 504 | static _jQueryInterface(config) { 505 | return this.each(function () { 506 | let data = $(this).data(DATA_KEY); 507 | 508 | const _config = typeof config === 'object' ? config : {}; 509 | _config.rootSelector = $(this).selector || _config.rootSelector; // this.selector removed in jQuery > 3 510 | 511 | if (!data && /destroy|hide/.test(config)) { 512 | return; 513 | } 514 | 515 | if (!data) { 516 | data = new Confirmation(this, _config); 517 | $(this).data(DATA_KEY, data); 518 | } 519 | 520 | if (typeof config === 'string') { 521 | if (typeof data[config] === 'undefined') { 522 | throw new TypeError(`No method named "${config}"`); 523 | } 524 | data[config](); 525 | } 526 | }); 527 | } 528 | } 529 | 530 | /** 531 | * ------------------------------------------------------------------------ 532 | * jQuery 533 | * ------------------------------------------------------------------------ 534 | */ 535 | 536 | $.fn[NAME] = Confirmation._jQueryInterface; 537 | $.fn[NAME].Constructor = Confirmation; 538 | $.fn[NAME].noConflict = function () { 539 | $.fn[NAME] = JQUERY_NO_CONFLICT; 540 | return Confirmation._jQueryInterface; 541 | }; 542 | 543 | export default Confirmation; 544 | -------------------------------------------------------------------------------- /src/popover.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | import 'bootstrap'; 3 | 4 | if (typeof $.fn.popover === 'undefined' || $.fn.popover.Constructor.VERSION.split('.').shift() !== '4') { 5 | throw new Error('Bootstrap Confirmation 4 requires Bootstrap Popover 4'); 6 | } 7 | 8 | const Popover = $.fn.popover.Constructor; 9 | 10 | export default Popover; 11 | --------------------------------------------------------------------------------