diff --git a/Gruntfile.js b/Gruntfile.js index f3c3af8f8e..09268ecb1f 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -56,27 +56,16 @@ module.exports = function (grunt) { docs: 'docs/dist' }, - jshint: { + babel: { options: { - jshintrc: 'js/.jshintrc' + sourceMap: true, + modules: 'ignore' }, - grunt: { - options: { - jshintrc: 'grunt/.jshintrc' - }, - src: ['Gruntfile.js', 'grunt/*.js'] - }, - core: { - src: 'js/*.js' - }, - test: { - options: { - jshintrc: 'js/tests/unit/.jshintrc' - }, - src: 'js/tests/unit/*.js' - }, - assets: { - src: ['docs/assets/js/src/*.js', 'docs/assets/js/*.js', '!docs/assets/js/*.min.js'] + dist: { + files: { + 'js/dist/util.js': 'js/src/util.js', + 'js/dist/alert.js': 'js/src/alert.js' + } } }, @@ -85,19 +74,22 @@ module.exports = function (grunt) { config: 'js/.jscsrc' }, grunt: { - src: '<%= jshint.grunt.src %>' + src: ['Gruntfile.js', 'grunt/*.js'] }, core: { - src: '<%= jshint.core.src %>' + src: 'js/*.js' + }, + es6: { + src: 'js/src/*.js' }, test: { - src: '<%= jshint.test.src %>' + src: 'js/tests/unit/*.js' }, assets: { options: { requireCamelCaseOrUpperCaseIdentifiers: null }, - src: '<%= jshint.assets.src %>' + src: ['docs/assets/js/src/*.js', 'docs/assets/js/*.js', '!docs/assets/js/*.min.js'] } }, @@ -301,12 +293,12 @@ module.exports = function (grunt) { watch: { src: { - files: '<%= jshint.core.src %>', - tasks: ['jshint:core', 'qunit', 'concat'] + files: '<%= jscs.core.src %>', + tasks: ['qunit', 'concat'] }, test: { - files: '<%= jshint.test.src %>', - tasks: ['jshint:test', 'qunit'] + files: '<%= jscs.test.src %>', + tasks: ['qunit'] }, sass: { files: 'scss/**/*.scss', @@ -398,7 +390,7 @@ module.exports = function (grunt) { testSubtasks.push('saucelabs-qunit'); } grunt.registerTask('test', testSubtasks); - grunt.registerTask('test-js', ['jshint:core', 'jshint:test', 'jshint:grunt', 'jscs:core', 'jscs:test', 'jscs:grunt', 'qunit']); + grunt.registerTask('test-js', ['jscs:core', 'jscs:test', 'jscs:grunt', 'qunit']); // JS distribution task. grunt.registerTask('dist-js', ['concat', 'uglify:core', 'commonjs']); @@ -434,7 +426,7 @@ module.exports = function (grunt) { // Docs task. grunt.registerTask('docs-css', ['autoprefixer:docs', 'autoprefixer:examples', 'csscomb:docs', 'csscomb:examples', 'cssmin:docs']); grunt.registerTask('docs-js', ['uglify:docsJs']); - grunt.registerTask('lint-docs-js', ['jshint:assets', 'jscs:assets']); + grunt.registerTask('lint-docs-js', ['jscs:assets']); grunt.registerTask('docs', ['docs-css', 'docs-js', 'lint-docs-js', 'clean:docs', 'copy:docs']); grunt.registerTask('docs-github', ['jekyll:github']); diff --git a/js/.jscsrc b/js/.jscsrc index 9544d2d2b5..8d5ef3e569 100644 --- a/js/.jscsrc +++ b/js/.jscsrc @@ -1,4 +1,5 @@ { + "esnext": true, "disallowEmptyBlocks": true, "disallowKeywords": ["with"], "disallowMixedSpacesAndTabs": true, diff --git a/js/.jshintrc b/js/.jshintrc deleted file mode 100644 index a59e1d00a1..0000000000 --- a/js/.jshintrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "asi" : true, - "browser" : true, - "eqeqeq" : false, - "eqnull" : true, - "es3" : true, - "expr" : true, - "jquery" : true, - "latedef" : true, - "laxbreak" : true, - "nonbsp" : true, - "strict" : true, - "undef" : true, - "unused" : true -} diff --git a/js/alert.js b/js/alert.js deleted file mode 100644 index 1925ef011c..0000000000 --- a/js/alert.js +++ /dev/null @@ -1,94 +0,0 @@ -/* ======================================================================== - * Bootstrap: alert.js v3.3.4 - * http://getbootstrap.com/javascript/#alerts - * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // ALERT CLASS DEFINITION - // ====================== - - var dismiss = '[data-dismiss="alert"]' - var Alert = function (el) { - $(el).on('click', dismiss, this.close) - } - - Alert.VERSION = '3.3.4' - - Alert.TRANSITION_DURATION = 150 - - Alert.prototype.close = function (e) { - var $this = $(this) - var selector = $this.attr('data-target') - - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 - } - - var $parent = $(selector) - - if (e) e.preventDefault() - - if (!$parent.length) { - $parent = $this.closest('.alert') - } - - $parent.trigger(e = $.Event('close.bs.alert')) - - if (e.isDefaultPrevented()) return - - $parent.removeClass('in') - - function removeElement() { - // detach from parent, fire event then clean up data - $parent.detach().trigger('closed.bs.alert').remove() - } - - $.support.transition && $parent.hasClass('fade') ? - $parent - .one('bsTransitionEnd', removeElement) - .emulateTransitionEnd(Alert.TRANSITION_DURATION) : - removeElement() - } - - - // ALERT PLUGIN DEFINITION - // ======================= - - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.alert') - - if (!data) $this.data('bs.alert', (data = new Alert(this))) - if (typeof option == 'string') data[option].call($this) - }) - } - - var old = $.fn.alert - - $.fn.alert = Plugin - $.fn.alert.Constructor = Alert - - - // ALERT NO CONFLICT - // ================= - - $.fn.alert.noConflict = function () { - $.fn.alert = old - return this - } - - - // ALERT DATA-API - // ============== - - $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) - -}(jQuery); diff --git a/js/dist/alert.js b/js/dist/alert.js new file mode 100644 index 0000000000..0dbfe767b7 --- /dev/null +++ b/js/dist/alert.js @@ -0,0 +1,170 @@ +'use strict'; + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +/** + * -------------------------------------------------------------------------- + * Constants + * -------------------------------------------------------------------------- + */ + +var NAME = 'alert'; +var VERSION = '4.0.0'; +var DATA_KEY = 'bs.alert'; +var JQUERY_NO_CONFLICT = $.fn[NAME]; +var TRANSITION_DURATION = 150; + +var Selector = { + DISMISS: '[data-dismiss="alert"]' +}; + +var Event = { + CLOSE: 'close.bs.alert', + CLOSED: 'closed.bs.alert', + CLICK: 'click.bs.alert.data-api' +}; + +var ClassName = { + ALERT: 'alert', + FADE: 'fade', + IN: 'in' +}; + +/** + * -------------------------------------------------------------------------- + * Class Definition + * -------------------------------------------------------------------------- + */ + +var Alert = (function () { + function Alert(element) { + _classCallCheck(this, Alert); + + if (element) { + this.element = element; + } + } + + _createClass(Alert, [{ + key: 'close', + + // public + + value: function close(element) { + var rootElement = this._getRootElement(element); + var customEvent = this._triggerCloseEvent(rootElement); + + if (customEvent.isDefaultPrevented()) { + return; + } + + this._removeElement(rootElement); + } + }, { + key: '_getRootElement', + + // private + + value: function _getRootElement(element) { + var parent = false; + var selector = Util.getSelectorFromElement(element); + + if (selector) { + parent = $(selector)[0]; + } + + if (!parent) { + parent = $(element).closest('.' + ClassName.ALERT)[0]; + } + + return parent; + } + }, { + key: '_triggerCloseEvent', + value: function _triggerCloseEvent(element) { + var closeEvent = $.Event(Event.CLOSE); + $(element).trigger(closeEvent); + return closeEvent; + } + }, { + key: '_removeElement', + value: function _removeElement(element) { + $(element).removeClass(ClassName.IN); + + if (!Util.supportsTransitionEnd() || !$(element).hasClass(ClassName.FADE)) { + this._destroyElement(element); + return; + } + + $(element).one(Util.TRANSITION_END, this._destroyElement.bind(this, element)).emulateTransitionEnd(TRANSITION_DURATION); + } + }, { + key: '_destroyElement', + value: function _destroyElement(element) { + $(element).detach().trigger(Event.CLOSED).remove(); + } + }], [{ + key: '_jQueryInterface', + + // static + + value: function _jQueryInterface(config) { + return this.each(function () { + var $element = $(this); + var data = $element.data(DATA_KEY); + + if (!data) { + data = new Alert(this); + $element.data(DATA_KEY, data); + } + + if (config === 'close') { + data[config](this); + } + }); + } + }, { + key: '_handleDismiss', + value: function _handleDismiss(alertInstance) { + return function (event) { + if (event) { + event.preventDefault(); + } + + alertInstance.close(this); + }; + } + }]); + + return Alert; +})(); + +/** + * -------------------------------------------------------------------------- + * Data Api implementation + * -------------------------------------------------------------------------- + */ + +$(document).on(Event.CLICK, Selector.DISMISS, Alert._handleDismiss(new Alert())); + +/** + * -------------------------------------------------------------------------- + * jQuery + * -------------------------------------------------------------------------- + */ + +$.fn[NAME] = Alert._jQueryInterface; +$.fn[NAME].Constructor = Alert; +$.fn[NAME].noConflict = function () { + $.fn[NAME] = Alert._JQUERY_NO_CONFLICT; + return Alert._jQueryInterface; +}; +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): alert.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ +//# sourceMappingURL=alert.js.map \ No newline at end of file diff --git a/js/dist/alert.js.map b/js/dist/alert.js.map new file mode 100644 index 0000000000..d2d9be6b6d --- /dev/null +++ b/js/dist/alert.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["js/src/alert.js"],"names":[],"mappings":";;;;;;;;;;;;AAgBA,IAAM,IAAI,GAAkB,OAAO,CAAA;AACnC,IAAM,OAAO,GAAe,OAAO,CAAA;AACnC,IAAM,QAAQ,GAAc,UAAU,CAAA;AACtC,IAAM,kBAAkB,GAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;AACtC,IAAM,mBAAmB,GAAG,GAAG,CAAA;;AAE/B,IAAM,QAAQ,GAAG;AACf,SAAO,EAAG,wBAAwB;CACnC,CAAA;;AAED,IAAM,KAAK,GAAG;AACZ,OAAK,EAAI,gBAAgB;AACzB,QAAM,EAAG,iBAAiB;AAC1B,OAAK,EAAI,yBAAyB;CACnC,CAAA;;AAED,IAAM,SAAS,GAAG;AAChB,OAAK,EAAG,OAAO;AACf,MAAI,EAAI,MAAM;AACd,IAAE,EAAM,IAAI;CACb,CAAA;;;;;;;;IASY,KAAK;AAEL,WAFA,KAAK,CAEJ,OAAO,EAAE;0BAFV,KAAK;;AAGd,QAAI,OAAO,EAAE;AACX,UAAI,CAAC,OAAO,GAAG,OAAO,CAAA;KACvB;GACF;;eANU,KAAK;;;;;WAWX,eAAC,OAAO,EAAE;AACb,UAAI,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;AAC/C,UAAI,WAAW,GAAG,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAA;;AAEtD,UAAI,WAAW,CAAC,kBAAkB,EAAE,EAAE;AACpC,eAAM;OACP;;AAED,UAAI,CAAC,cAAc,CAAC,WAAW,CAAC,CAAA;KACjC;;;;;;WAKc,yBAAC,OAAO,EAAE;AACvB,UAAI,MAAM,GAAK,KAAK,CAAA;AACpB,UAAI,QAAQ,GAAG,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAA;;AAEnD,UAAI,QAAQ,EAAE;AACZ,cAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;OACxB;;AAED,UAAI,CAAC,MAAM,EAAE;AACX,cAAM,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;OACtD;;AAED,aAAO,MAAM,CAAA;KACd;;;WAEiB,4BAAC,OAAO,EAAE;AAC1B,UAAI,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;AACrC,OAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;AAC9B,aAAO,UAAU,CAAA;KAClB;;;WAEa,wBAAC,OAAO,EAAE;AACtB,OAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;;AAEpC,UAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;AACzE,YAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;AAC7B,eAAM;OACP;;AAED,OAAC,CAAC,OAAO,CAAC,CACP,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAClE,oBAAoB,CAAC,mBAAmB,CAAC,CAAA;KAC7C;;;WAEc,yBAAC,OAAO,EAAE;AACvB,OAAC,CAAC,OAAO,CAAC,CACP,MAAM,EAAE,CACR,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CACrB,MAAM,EAAE,CAAA;KACZ;;;;;;WAKsB,0BAAC,MAAM,EAAE;AAC9B,aAAO,IAAI,CAAC,IAAI,CAAC,YAAY;AAC3B,YAAI,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,CAAA;AACtB,YAAI,IAAI,GAAO,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;;AAEtC,YAAI,CAAC,IAAI,EAAE;AACT,cAAI,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,CAAA;AACtB,kBAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;SAC9B;;AAED,YAAI,MAAM,KAAK,OAAO,EAAE;AACtB,cAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAA;SACnB;OACF,CAAC,CAAA;KACH;;;WAEoB,wBAAC,aAAa,EAAE;AACnC,aAAO,UAAU,KAAK,EAAE;AACtB,YAAI,KAAK,EAAE;AACT,eAAK,CAAC,cAAc,EAAE,CAAA;SACvB;;AAED,qBAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;OAC1B,CAAA;KACF;;;SA7FU,KAAK;;;;;;;;;AAwGlB,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CACZ,KAAK,CAAC,KAAK,EACX,QAAQ,CAAC,OAAO,EAChB,KAAK,CAAC,cAAc,CAAC,IAAI,KAAK,EAAE,CAAC,CAClC,CAAA;;;;;;;;AASD,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAe,KAAK,CAAC,gBAAgB,CAAA;AAC/C,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,WAAW,GAAG,KAAK,CAAA;AAC9B,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,UAAU,GAAI,YAAY;AACnC,GAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,mBAAmB,CAAA;AACtC,SAAO,KAAK,CAAC,gBAAgB,CAAA;CAC9B,CAAA","file":"js/src/alert.js","sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.0.0): alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Util from 'util'\n\n\n/**\n * --------------------------------------------------------------------------\n * Constants\n * --------------------------------------------------------------------------\n */\n\nconst NAME = 'alert'\nconst VERSION = '4.0.0'\nconst DATA_KEY = 'bs.alert'\nconst JQUERY_NO_CONFLICT = $.fn[NAME]\nconst TRANSITION_DURATION = 150\n\nconst Selector = {\n DISMISS : '[data-dismiss=\"alert\"]'\n}\n\nconst Event = {\n CLOSE : 'close.bs.alert',\n CLOSED : 'closed.bs.alert',\n CLICK : 'click.bs.alert.data-api'\n}\n\nconst ClassName = {\n ALERT : 'alert',\n FADE : 'fade',\n IN : 'in'\n}\n\n\n/**\n * --------------------------------------------------------------------------\n * Class Definition\n * --------------------------------------------------------------------------\n */\n\nexport class Alert {\n\n constructor(element) {\n if (element) {\n this.element = element\n }\n }\n\n\n // public\n\n close(element) {\n let rootElement = this._getRootElement(element)\n let customEvent = this._triggerCloseEvent(rootElement)\n\n if (customEvent.isDefaultPrevented()) {\n return\n }\n\n this._removeElement(rootElement)\n }\n\n\n // private\n\n _getRootElement(element) {\n let parent = false\n let selector = Util.getSelectorFromElement(element)\n\n if (selector) {\n parent = $(selector)[0]\n }\n\n if (!parent) {\n parent = $(element).closest('.' + ClassName.ALERT)[0]\n }\n\n return parent\n }\n\n _triggerCloseEvent(element) {\n var closeEvent = $.Event(Event.CLOSE)\n $(element).trigger(closeEvent)\n return closeEvent\n }\n\n _removeElement(element) {\n $(element).removeClass(ClassName.IN)\n\n if (!Util.supportsTransitionEnd() || !$(element).hasClass(ClassName.FADE)) {\n this._destroyElement(element)\n return\n }\n\n $(element)\n .one(Util.TRANSITION_END, this._destroyElement.bind(this, element))\n .emulateTransitionEnd(TRANSITION_DURATION)\n }\n\n _destroyElement(element) {\n $(element)\n .detach()\n .trigger(Event.CLOSED)\n .remove()\n }\n\n\n // static\n\n static _jQueryInterface(config) {\n return this.each(function () {\n let $element = $(this)\n let data = $element.data(DATA_KEY)\n\n if (!data) {\n data = new Alert(this)\n $element.data(DATA_KEY, data)\n }\n\n if (config === 'close') {\n data[config](this)\n }\n })\n }\n\n static _handleDismiss(alertInstance) {\n return function (event) {\n if (event) {\n event.preventDefault()\n }\n\n alertInstance.close(this)\n }\n }\n\n}\n\n\n/**\n * --------------------------------------------------------------------------\n * Data Api implementation\n * --------------------------------------------------------------------------\n */\n\n$(document).on(\n Event.CLICK,\n Selector.DISMISS,\n Alert._handleDismiss(new Alert())\n)\n\n\n/**\n * --------------------------------------------------------------------------\n * jQuery\n * --------------------------------------------------------------------------\n */\n\n$.fn[NAME] = Alert._jQueryInterface\n$.fn[NAME].Constructor = Alert\n$.fn[NAME].noConflict = function () {\n $.fn[NAME] = Alert._JQUERY_NO_CONFLICT\n return Alert._jQueryInterface\n}\n"]} \ No newline at end of file diff --git a/js/dist/util.js b/js/dist/util.js new file mode 100644 index 0000000000..48865c5d76 --- /dev/null +++ b/js/dist/util.js @@ -0,0 +1,124 @@ +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): util.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + +/** + * ------------------------------------------------------------------------ + * Public Util Api + * ------------------------------------------------------------------------ + */ + +'use strict'; + +var Util = { + + TRANSITION_END: 'bsTransitionEnd', + + getUID: function getUID(prefix) { + do prefix += ~ ~(Math.random() * 1000000); while (document.getElementById(prefix)); + return prefix; + }, + + getSelectorFromElement: function getSelectorFromElement(element) { + var selector = element.getAttribute('data-target'); + + if (!selector) { + selector = element.getAttribute('href') || ''; + selector = /^#[a-z]/i.test(selector) ? selector : null; + } + + return selector; + }, + + reflow: function reflow(element) { + new Function('bs', 'return bs')(element.offsetHeight); + }, + + supportsTransitionEnd: function supportsTransitionEnd() { + return !!transition; + } + +}; + +/** + * ------------------------------------------------------------------------ + * Private TransitionEnd Helpers + * ------------------------------------------------------------------------ + */ + +var transition = false; + +var TransitionEndEvent = { + WebkitTransition: 'webkitTransitionEnd', + MozTransition: 'transitionend', + OTransition: 'oTransitionEnd otransitionend', + transition: 'transitionend' +}; + +function getSpecialTransitionEndEvent() { + return { + bindType: transition.end, + delegateType: transition.end, + handle: function handle(event) { + if ($(event.target).is(this)) { + return event.handleObj.handler.apply(this, arguments); + } + } + }; +} + +function transitionEndTest() { + if (window.QUnit) { + return false; + } + + var el = document.createElement('bootstrap'); + + for (var name in TransitionEndEvent) { + if (el.style[name] !== undefined) { + return { end: TransitionEndEvent[name] }; + } + } + + return false; +} + +function transitionEndEmulator(duration) { + var _this = this; + + var called = false; + + $(this).one(Util.TRANSITION_END, function () { + called = true; + }); + + setTimeout(function () { + if (!called) { + $(_this).trigger(transition.end); + } + }, duration); + + return this; +} + +function setTransitionEndSupport() { + transition = transitionEndTest(); + + $.fn.emulateTransitionEnd = transitionEndEmulator; + + if (Util.supportsTransitionEnd()) { + $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent(); + } +} + +setTransitionEndSupport(); + +/** + * ------------------------------------------------------------------------ + * Export Api + * ------------------------------------------------------------------------ + */ +//# sourceMappingURL=util.js.map \ No newline at end of file diff --git a/js/dist/util.js.map b/js/dist/util.js.map new file mode 100644 index 0000000000..5de0badbd7 --- /dev/null +++ b/js/dist/util.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["js/src/util.js"],"names":[],"mappings":"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","file":"js/src/util.js","sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.0.0): util.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * ------------------------------------------------------------------------\n * Public Util Api\n * ------------------------------------------------------------------------\n */\n\nvar Util = {\n\n TRANSITION_END: 'bsTransitionEnd',\n\n getUID(prefix) {\n do prefix += ~~(Math.random() * 1000000)\n while (document.getElementById(prefix))\n return prefix\n },\n\n getSelectorFromElement(element) {\n let selector = element.getAttribute('data-target')\n\n if (!selector) {\n selector = element.getAttribute('href') || ''\n selector = /^#[a-z]/i.test(selector) ? selector : null\n }\n\n return selector\n },\n\n reflow(element) {\n new Function('bs', 'return bs')(element.offsetHeight)\n },\n\n supportsTransitionEnd() {\n return !!transition\n }\n\n}\n\n\n/**\n * ------------------------------------------------------------------------\n * Private TransitionEnd Helpers\n * ------------------------------------------------------------------------\n */\n\nlet transition = false\n\nconst TransitionEndEvent = {\n WebkitTransition : 'webkitTransitionEnd',\n MozTransition : 'transitionend',\n OTransition : 'oTransitionEnd otransitionend',\n transition : 'transitionend'\n}\n\nfunction getSpecialTransitionEndEvent() {\n return {\n bindType: transition.end,\n delegateType: transition.end,\n handle: function (event) {\n if ($(event.target).is(this)) {\n return event.handleObj.handler.apply(this, arguments)\n }\n }\n }\n}\n\nfunction transitionEndTest() {\n if (window.QUnit) {\n return false\n }\n\n let el = document.createElement('bootstrap')\n\n for (var name in TransitionEndEvent) {\n if (el.style[name] !== undefined) {\n return { end: TransitionEndEvent[name] }\n }\n }\n\n return false\n}\n\nfunction transitionEndEmulator(duration) {\n let called = false\n\n $(this).one(Util.TRANSITION_END, function () {\n called = true\n })\n\n setTimeout(() => {\n if (!called) {\n $(this).trigger(transition.end)\n }\n }, duration)\n\n return this\n}\n\nfunction setTransitionEndSupport() {\n transition = transitionEndTest()\n\n $.fn.emulateTransitionEnd = transitionEndEmulator\n\n if (Util.supportsTransitionEnd()) {\n $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent()\n }\n}\n\nsetTransitionEndSupport()\n\n\n/**\n * ------------------------------------------------------------------------\n * Export Api\n * ------------------------------------------------------------------------\n */\n\nexport default Util\n"]} \ No newline at end of file diff --git a/js/src/alert.js b/js/src/alert.js new file mode 100644 index 0000000000..bd12b1a559 --- /dev/null +++ b/js/src/alert.js @@ -0,0 +1,168 @@ +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): alert.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + +import Util from 'util' + + +/** + * -------------------------------------------------------------------------- + * Constants + * -------------------------------------------------------------------------- + */ + +const NAME = 'alert' +const VERSION = '4.0.0' +const DATA_KEY = 'bs.alert' +const JQUERY_NO_CONFLICT = $.fn[NAME] +const TRANSITION_DURATION = 150 + +const Selector = { + DISMISS : '[data-dismiss="alert"]' +} + +const Event = { + CLOSE : 'close.bs.alert', + CLOSED : 'closed.bs.alert', + CLICK : 'click.bs.alert.data-api' +} + +const ClassName = { + ALERT : 'alert', + FADE : 'fade', + IN : 'in' +} + + +/** + * -------------------------------------------------------------------------- + * Class Definition + * -------------------------------------------------------------------------- + */ + +export class Alert { + + constructor(element) { + if (element) { + this.element = element + } + } + + + // public + + close(element) { + let rootElement = this._getRootElement(element) + let customEvent = this._triggerCloseEvent(rootElement) + + if (customEvent.isDefaultPrevented()) { + return + } + + this._removeElement(rootElement) + } + + + // private + + _getRootElement(element) { + let parent = false + let selector = Util.getSelectorFromElement(element) + + if (selector) { + parent = $(selector)[0] + } + + if (!parent) { + parent = $(element).closest('.' + ClassName.ALERT)[0] + } + + return parent + } + + _triggerCloseEvent(element) { + var closeEvent = $.Event(Event.CLOSE) + $(element).trigger(closeEvent) + return closeEvent + } + + _removeElement(element) { + $(element).removeClass(ClassName.IN) + + if (!Util.supportsTransitionEnd() || !$(element).hasClass(ClassName.FADE)) { + this._destroyElement(element) + return + } + + $(element) + .one(Util.TRANSITION_END, this._destroyElement.bind(this, element)) + .emulateTransitionEnd(TRANSITION_DURATION) + } + + _destroyElement(element) { + $(element) + .detach() + .trigger(Event.CLOSED) + .remove() + } + + + // static + + static _jQueryInterface(config) { + return this.each(function () { + let $element = $(this) + let data = $element.data(DATA_KEY) + + if (!data) { + data = new Alert(this) + $element.data(DATA_KEY, data) + } + + if (config === 'close') { + data[config](this) + } + }) + } + + static _handleDismiss(alertInstance) { + return function (event) { + if (event) { + event.preventDefault() + } + + alertInstance.close(this) + } + } + +} + + +/** + * -------------------------------------------------------------------------- + * Data Api implementation + * -------------------------------------------------------------------------- + */ + +$(document).on( + Event.CLICK, + Selector.DISMISS, + Alert._handleDismiss(new Alert()) +) + + +/** + * -------------------------------------------------------------------------- + * jQuery + * -------------------------------------------------------------------------- + */ + +$.fn[NAME] = Alert._jQueryInterface +$.fn[NAME].Constructor = Alert +$.fn[NAME].noConflict = function () { + $.fn[NAME] = Alert._JQUERY_NO_CONFLICT + return Alert._jQueryInterface +} diff --git a/js/src/util.js b/js/src/util.js new file mode 100644 index 0000000000..e9542149e6 --- /dev/null +++ b/js/src/util.js @@ -0,0 +1,118 @@ +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): util.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + + +/** + * -------------------------------------------------------------------------- + * Public Util Api + * -------------------------------------------------------------------------- + */ + +var Util = { + + TRANSITION_END: 'bsTransitionEnd', + + getUID(prefix) { + do prefix += ~~(Math.random() * 1000000) + while (document.getElementById(prefix)) + return prefix + }, + + getSelectorFromElement(element) { + let selector = element.getAttribute('data-target') + + if (!selector) { + selector = element.getAttribute('href') || '' + selector = /^#[a-z]/i.test(selector) ? selector : null + } + + return selector + }, + + reflow(element) { + new Function('bs', 'return bs')(element.offsetHeight) + }, + + supportsTransitionEnd() { + return !!transition + } + +} + +export default Util + + +/** + * -------------------------------------------------------------------------- + * Private TransitionEnd Helpers + * -------------------------------------------------------------------------- + */ + +let transition = false + +const TransitionEndEvent = { + WebkitTransition : 'webkitTransitionEnd', + MozTransition : 'transitionend', + OTransition : 'oTransitionEnd otransitionend', + transition : 'transitionend' +} + +function getSpecialTransitionEndEvent() { + return { + bindType: transition.end, + delegateType: transition.end, + handle: function (event) { + if ($(event.target).is(this)) { + return event.handleObj.handler.apply(this, arguments) + } + } + } +} + +function transitionEndTest() { + if (window.QUnit) { + return false + } + + let el = document.createElement('bootstrap') + + for (var name in TransitionEndEvent) { + if (el.style[name] !== undefined) { + return { end: TransitionEndEvent[name] } + } + } + + return false +} + +function transitionEndEmulator(duration) { + let called = false + + $(this).one(Util.TRANSITION_END, function () { + called = true + }) + + setTimeout(() => { + if (!called) { + $(this).trigger(transition.end) + } + }, duration) + + return this +} + +function setTransitionEndSupport() { + transition = transitionEndTest() + + $.fn.emulateTransitionEnd = transitionEndEmulator + + if (Util.supportsTransitionEnd()) { + $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent() + } +} + +setTransitionEndSupport() diff --git a/js/tests/index.html b/js/tests/index.html index fab2ebc163..536e34c747 100644 --- a/js/tests/index.html +++ b/js/tests/index.html @@ -129,9 +129,11 @@ })(); - - - + + + + + diff --git a/js/tests/unit/alert.js b/js/tests/unit/alert.js index 6be990a518..97818960ac 100644 --- a/js/tests/unit/alert.js +++ b/js/tests/unit/alert.js @@ -38,7 +38,8 @@ $(function () { + '×' + '
Holy guacamole! Best check yo self, you\'re not looking too good.
' + '' - var $alert = $(alertHTML).bootstrapAlert() + + var $alert = $(alertHTML).bootstrapAlert().appendTo($('#qunit-fixture')) $alert.find('.close').trigger('click') diff --git a/js/tests/visual/alert.html b/js/tests/visual/alert.html index 0070315a24..9e6a939e96 100644 --- a/js/tests/visual/alert.html +++ b/js/tests/visual/alert.html @@ -41,8 +41,8 @@ - - + +