From 7e31a8104d73dfc42e1c695a39aeb853a03a33fb Mon Sep 17 00:00:00 2001 From: Kelv Date: Wed, 12 Jun 2024 15:56:17 +0800 Subject: [PATCH] DEV: remove bootbox dependency (#27443) --- .../instance-initializers/jquery-plugins.js | 42 - .../app/instance-initializers/localization.js | 8 - .../javascripts/discourse/ember-cli-build.js | 17 - .../discourse/tests/setup-tests.js | 32 - app/assets/stylesheets/common/base/modal.scss | 10 - app/assets/stylesheets/desktop/modal.scss | 11 - app/assets/stylesheets/mobile/modal.scss | 6 - vendor/assets/javascripts/bootbox.js | 719 ------------------ 8 files changed, 845 deletions(-) delete mode 100644 vendor/assets/javascripts/bootbox.js diff --git a/app/assets/javascripts/discourse/app/instance-initializers/jquery-plugins.js b/app/assets/javascripts/discourse/app/instance-initializers/jquery-plugins.js index b5668043349..44f9bf44058 100644 --- a/app/assets/javascripts/discourse/app/instance-initializers/jquery-plugins.js +++ b/app/assets/javascripts/discourse/app/instance-initializers/jquery-plugins.js @@ -1,10 +1,6 @@ -import "bootstrap/js/modal"; -import bootbox from "bootbox"; import $ from "jquery"; import autocomplete from "discourse/lib/autocomplete"; import { caret, caretPosition } from "discourse/lib/caret-position"; -import deprecated from "discourse-common/lib/deprecated"; -import { getOwnerWithFallback } from "discourse-common/lib/get-owner"; let jqueryPluginsConfigured = false; @@ -14,44 +10,6 @@ export default { return; } - // Settings for bootbox - bootbox.animate(false); - bootbox.backdrop(true); - - // Monkey-patching simple alerts - const originalAlert = bootbox.alert; - bootbox.alert = function () { - if (arguments.length === 1) { - const dialog = getOwnerWithFallback(this).lookup("service:dialog"); - if (dialog) { - deprecated( - "`bootbox.alert` is deprecated, please use the dialog service instead.", - { - id: "discourse.bootbox", - dropFrom: "3.1.0.beta5", - url: "https://meta.discourse.org/t/244902", - } - ); - return dialog.alert(arguments[0]); - } - } - return originalAlert(...arguments); - }; - - // adding deprecation notice for all other dialogs - const originalDialog = bootbox.dialog; - bootbox.dialog = function () { - deprecated( - "`bootbox` is now deprecated, please use the dialog service instead.", - { - id: "discourse.bootbox", - dropFrom: "3.1.0.beta5", - url: "https://meta.discourse.org/t/244902", - } - ); - return originalDialog(...arguments); - }; - // Initialize the autocomplete tool $.fn.autocomplete = autocomplete; diff --git a/app/assets/javascripts/discourse/app/instance-initializers/localization.js b/app/assets/javascripts/discourse/app/instance-initializers/localization.js index 5832d8e0078..8d07056e2bb 100644 --- a/app/assets/javascripts/discourse/app/instance-initializers/localization.js +++ b/app/assets/javascripts/discourse/app/instance-initializers/localization.js @@ -1,4 +1,3 @@ -import bootbox from "bootbox"; import I18n from "discourse-i18n"; export default { @@ -45,12 +44,5 @@ export default { key = key.replace(/^[a-z_]*js\./, ""); I18n._compiledMFs[key] = value; } - - bootbox.addLocale(I18n.currentLocale(), { - OK: I18n.t("composer.modal_ok"), - CANCEL: I18n.t("composer.modal_cancel"), - CONFIRM: I18n.t("composer.modal_ok"), - }); - bootbox.setLocale(I18n.currentLocale()); }, }; diff --git a/app/assets/javascripts/discourse/ember-cli-build.js b/app/assets/javascripts/discourse/ember-cli-build.js index e2594ad9106..180381fed28 100644 --- a/app/assets/javascripts/discourse/ember-cli-build.js +++ b/app/assets/javascripts/discourse/ember-cli-build.js @@ -78,7 +78,6 @@ module.exports = function (defaults) { }); // WARNING: We should only import scripts here if they are not in NPM. - app.import(vendorJs + "bootbox.js"); app.import(discourseRoot + "/app/assets/javascripts/polyfills.js"); app.import( @@ -178,22 +177,6 @@ module.exports = function (defaults) { exportsPresence: "error", }, }, - rules: [ - { - test: require.resolve("bootstrap/js/modal"), - use: [ - { - loader: "imports-loader", - options: { - imports: { - moduleName: "jquery", - name: "jQuery", - }, - }, - }, - ], - }, - ], }, plugins: [ // The server use this output to map each asset to its chunks diff --git a/app/assets/javascripts/discourse/tests/setup-tests.js b/app/assets/javascripts/discourse/tests/setup-tests.js index e8bb5686590..40ce021596d 100644 --- a/app/assets/javascripts/discourse/tests/setup-tests.js +++ b/app/assets/javascripts/discourse/tests/setup-tests.js @@ -10,8 +10,6 @@ import { setApplication, setResolver, } from "@ember/test-helpers"; -import "bootstrap/js/modal"; -import bootbox from "bootbox"; import { addModuleExcludeMatcher } from "ember-cli-test-loader/test-support/index"; import $ from "jquery"; import MessageBus from "message-bus-client"; @@ -51,34 +49,7 @@ import { loadSprites } from "../lib/svg-sprite-loader"; import * as FakerModule from "@faker-js/faker"; import { setLoadedFaker } from "discourse/lib/load-faker"; -const Plugin = $.fn.modal; -const Modal = Plugin.Constructor; let cancelled = false; - -function AcceptanceModal(option, _relatedTarget) { - return this.each(function () { - let $this = $(this); - let data = $this.data("bs.modal"); - let options = Object.assign( - {}, - Modal.DEFAULTS, - $this.data(), - typeof option === "object" && option - ); - - if (!data) { - $this.data("bs.modal", (data = new Modal(this, options))); - } - data.$body = $("#ember-testing"); - - if (typeof option === "string") { - data[option](_relatedTarget); - } else if (options.show) { - data.show(_relatedTarget); - } - }); -} - let started = false; function createApplication(config, settings) { @@ -255,8 +226,6 @@ export default function setupTests(config) { window.Logster = { enabled: false }; } - $.fn.modal = AcceptanceModal; - Object.defineProperty(window, "exists", { get() { deprecated( @@ -280,7 +249,6 @@ export default function setupTests(config) { let app; QUnit.testStart(function (ctx) { - bootbox.$body = $("#ember-testing"); let settings = resetSettings(); resetThemeSettings(); diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index a1d120e24d2..b2557c09e2d 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -151,16 +151,6 @@ } } -.bootbox.modal { - position: fixed; - z-index: z("modal", "content"); - overflow: auto; - height: auto; - background-color: var(--secondary); - box-shadow: var(--shadow-card); - background-clip: padding-box; -} - .input-hint-text { margin-left: 0.5em; color: var(--secondary-high); diff --git a/app/assets/stylesheets/desktop/modal.scss b/app/assets/stylesheets/desktop/modal.scss index 55f7142214a..0b4ae433c77 100644 --- a/app/assets/stylesheets/desktop/modal.scss +++ b/app/assets/stylesheets/desktop/modal.scss @@ -13,17 +13,6 @@ } } } -//legacy -// Hardcode to be the same as before for now. I would recommend not using bootbox, or finding a way so the html structure can be the same -.bootbox.modal { - top: 50%; - left: 50%; - width: 610px; - margin: -250px 0 0 -305px; - .cancel { - margin-left: 1em; - } -} .modal.in { animation: fade 0.25s; diff --git a/app/assets/stylesheets/mobile/modal.scss b/app/assets/stylesheets/mobile/modal.scss index 5a8ad7a3541..b4d6a937dcf 100644 --- a/app/assets/stylesheets/mobile/modal.scss +++ b/app/assets/stylesheets/mobile/modal.scss @@ -72,12 +72,6 @@ html:not(.keyboard-visible.mobile-view) { margin-bottom: 30px; // For iOS Safari issues } -// Hardcode to be the same as before for now. I would recommend not using bootbox, or finding a way so the html structure can be the same -.bootbox.modal { - top: 10%; - width: 100%; -} - .modal { &.fade { transition: opacity 0.3s linear, top 0.3s ease-out; diff --git a/vendor/assets/javascripts/bootbox.js b/vendor/assets/javascripts/bootbox.js deleted file mode 100644 index a9b65e34fc8..00000000000 --- a/vendor/assets/javascripts/bootbox.js +++ /dev/null @@ -1,719 +0,0 @@ -define("bootbox", ["jquery", "exports"], function (jQuery, __exports__) { - if ("bootbox" in window) { - throw new Error("bootbox unexpectedly loaded twice!"); - } - - /** - * bootbox.js v3.2.0 - * - * http://bootboxjs.com/license.txt - */ - var bootbox = - window.bootbox || - (function (document, $) { - /*jshint scripturl:true sub:true */ - - var _locale = "en", - _defaultLocale = "en", - _animate = true, - _backdrop = "static", - _defaultHref = "javascript:;", - _classes = "", - _btnClasses = {}, - _icons = {}, - /* last var should always be the public object we'll return */ - that = {}; - - /** - * public API - */ - that.setLocale = function (locale) { - for (var i in _locales) { - if (i == locale) { - _locale = locale; - return; - } - } - throw new Error("Invalid locale: " + locale); - }; - - that.addLocale = function (locale, translations) { - if (typeof _locales[locale] === "undefined") { - _locales[locale] = {}; - } - for (var str in translations) { - _locales[locale][str] = translations[str]; - } - }; - - that.setIcons = function (icons) { - _icons = icons; - if (typeof _icons !== "object" || _icons === null) { - _icons = {}; - } - }; - - that.setBtnClasses = function (btnClasses) { - _btnClasses = btnClasses; - if (typeof _btnClasses !== "object" || _btnClasses === null) { - _btnClasses = {}; - } - }; - - that.alert = function (/*str, label, cb*/) { - var str = "", - label = _translate("OK"), - cb = null; - - switch (arguments.length) { - case 1: - // no callback, default button label - str = arguments[0]; - break; - case 2: - // callback *or* custom button label dependent on type - str = arguments[0]; - if (typeof arguments[1] == "function") { - cb = arguments[1]; - } else { - label = arguments[1]; - } - break; - case 3: - // callback and custom button label - str = arguments[0]; - label = arguments[1]; - cb = arguments[2]; - break; - default: - throw new Error("Incorrect number of arguments: expected 1-3"); - } - - return that.dialog( - str, - { - // only button (ok) - label: label, - icon: _icons.OK, - class: _btnClasses.OK, - callback: cb, - }, - { - // ensure that the escape key works; either invoking the user's - // callback or true to just close the dialog - onEscape: cb || true, - } - ); - }; - - that.confirm = function (/*str, labelCancel, labelOk, cb*/) { - var str = "", - labelCancel = _translate("CANCEL"), - labelOk = _translate("CONFIRM"), - cb = null; - - switch (arguments.length) { - case 1: - str = arguments[0]; - break; - case 2: - str = arguments[0]; - if (typeof arguments[1] == "function") { - cb = arguments[1]; - } else { - labelCancel = arguments[1]; - } - break; - case 3: - str = arguments[0]; - labelCancel = arguments[1]; - if (typeof arguments[2] == "function") { - cb = arguments[2]; - } else { - labelOk = arguments[2]; - } - break; - case 4: - str = arguments[0]; - labelCancel = arguments[1]; - labelOk = arguments[2]; - cb = arguments[3]; - break; - default: - throw new Error("Incorrect number of arguments: expected 1-4"); - } - - var cancelCallback = function () { - if (typeof cb === "function") { - return cb(false); - } - }; - - var confirmCallback = function () { - if (typeof cb === "function") { - return cb(true); - } - }; - - return that.dialog( - str, - [ - { - // first button (cancel) - label: labelCancel, - icon: _icons.CANCEL, - class: _btnClasses.CANCEL, - callback: cancelCallback, - }, - { - // second button (confirm) - label: labelOk, - icon: _icons.CONFIRM, - class: _btnClasses.CONFIRM, - callback: confirmCallback, - }, - ], - { - // escape key bindings - onEscape: cancelCallback, - } - ); - }; - - that.prompt = function (/*str, labelCancel, labelOk, cb, defaultVal*/) { - var str = "", - labelCancel = _translate("CANCEL"), - labelOk = _translate("CONFIRM"), - cb = null, - defaultVal = ""; - - switch (arguments.length) { - case 1: - str = arguments[0]; - break; - case 2: - str = arguments[0]; - if (typeof arguments[1] == "function") { - cb = arguments[1]; - } else { - labelCancel = arguments[1]; - } - break; - case 3: - str = arguments[0]; - labelCancel = arguments[1]; - if (typeof arguments[2] == "function") { - cb = arguments[2]; - } else { - labelOk = arguments[2]; - } - break; - case 4: - str = arguments[0]; - labelCancel = arguments[1]; - labelOk = arguments[2]; - cb = arguments[3]; - break; - case 5: - str = arguments[0]; - labelCancel = arguments[1]; - labelOk = arguments[2]; - cb = arguments[3]; - defaultVal = arguments[4]; - break; - default: - throw new Error("Incorrect number of arguments: expected 1-5"); - } - - var header = str; - - // let's keep a reference to the form object for later - var form = $("
"); - form.append( - "" - ); - - var cancelCallback = function () { - if (typeof cb === "function") { - // yep, native prompts dismiss with null, whereas native - // confirms dismiss with false... - return cb(null); - } - }; - - var confirmCallback = function () { - if (typeof cb === "function") { - return cb(form.find("input[type=text]").val()); - } - }; - - var div = that.dialog( - form, - [ - { - // first button (cancel) - label: labelCancel, - icon: _icons.CANCEL, - class: _btnClasses.CANCEL, - callback: cancelCallback, - }, - { - // second button (confirm) - label: labelOk, - icon: _icons.CONFIRM, - class: _btnClasses.CONFIRM, - callback: confirmCallback, - }, - ], - { - // prompts need a few extra options - header: header, - // explicitly tell dialog NOT to show the dialog... - show: false, - onEscape: cancelCallback, - } - ); - - // ... the reason the prompt needs to be hidden is because we need - // to bind our own "shown" handler, after creating the modal but - // before any show(n) events are triggered - // @see https://github.com/makeusabrew/bootbox/issues/69 - - div.on("shown", function () { - form.find("input[type=text]").focus(); - - // ensure that submitting the form (e.g. with the enter key) - // replicates the behaviour of a normal prompt() - form.on("submit", function (e) { - e.preventDefault(); - div.find(".btn-primary").click(); - }); - }); - - div.modal("show"); - - return div; - }; - - that.dialog = function (str, handlers, options) { - var buttons = "", - callbacks = []; - - if (!options) { - options = {}; - } - - // check for single object and convert to array if necessary - if (typeof handlers === "undefined") { - handlers = []; - } else if (typeof handlers.length == "undefined") { - handlers = [handlers]; - } - - var i = handlers.length; - while (i--) { - var label = null, - href = null, - _class = "btn-default", - icon = "", - callback = null; - - if ( - typeof handlers[i]["label"] == "undefined" && - typeof handlers[i]["class"] == "undefined" && - typeof handlers[i]["callback"] == "undefined" - ) { - // if we've got nothing we expect, check for condensed format - - var propCount = 0, // condensed will only match if this == 1 - property = null; // save the last property we found - - // be nicer to count the properties without this, but don't think it's possible... - for (var j in handlers[i]) { - property = j; - if (++propCount > 1) { - // forget it, too many properties - break; - } - } - - if (propCount == 1 && typeof handlers[i][j] == "function") { - // matches condensed format of label -> function - handlers[i]["label"] = property; - handlers[i]["callback"] = handlers[i][j]; - } - } - - if (typeof handlers[i]["callback"] == "function") { - callback = handlers[i]["callback"]; - } - - if (handlers[i]["class"]) { - _class = handlers[i]["class"]; - } else if (i == handlers.length - 1 && handlers.length <= 2) { - // always add a primary to the main option in a two-button dialog - _class = "btn-primary"; - } - - // See: https://github.com/makeusabrew/bootbox/pull/114 - // Upgrade to official bootbox release when it gets merged. - if (handlers[i]["link"] !== true) { - _class = "btn " + _class; - } - - if (handlers[i]["label"]) { - label = handlers[i]["label"]; - } else { - label = "Option " + (i + 1); - } - - if (handlers[i]["icon"]) { - icon = handlers[i]["icon"]; - } - - if (handlers[i]["href"]) { - href = handlers[i]["href"]; - } else { - href = _defaultHref; - } - - buttons = - buttons + - "" + - icon + - "" + - label + - ""; - - callbacks[i] = callback; - } - - // @see https://github.com/makeusabrew/bootbox/issues/46#issuecomment-8235302 - // and https://github.com/twitter/bootstrap/issues/4474 - // for an explanation of the inline overflow: hidden - // @see https://github.com/twitter/bootstrap/issues/4854 - // for an explanation of tabIndex=-1 - - var parts = [ - ""); - - var div = $(parts.join("\n")); - - // check whether we should fade in/out - var shouldFade = - typeof options.animate === "undefined" ? _animate : options.animate; - - if (shouldFade) { - div.addClass("fade"); - } - - var optionalClasses = - typeof options.classes === "undefined" ? _classes : options.classes; - if (optionalClasses) { - div.addClass(optionalClasses); - } - - // now we've built up the div properly we can inject the content whether it was a string or a jQuery object - div.find(".modal-body").html(str); - - function onCancel(source) { - // for now source is unused, but it will be in future - var hideModal = null; - if (typeof options.onEscape === "function") { - // @see https://github.com/makeusabrew/bootbox/issues/91 - hideModal = options.onEscape(); - } - - if (hideModal !== false) { - div.modal("hide"); - } - } - - // hook into the modal's keyup trigger to check for the escape key - div.on("keyup.dismiss.modal", function (e) { - // any truthy value passed to onEscape will dismiss the dialog - // as long as the onEscape function (if defined) doesn't prevent it - if (e.which === 27 && options.onEscape !== false) { - onCancel("escape"); - } - }); - - // handle close buttons too - div.on("click", "a.close", function (e) { - e.preventDefault(); - onCancel("close"); - }); - - // well, *if* we have a primary - give the first dom element focus - div.on("shown.bs.modal", function () { - div.find("a.btn-primary:first").focus(); - }); - - div.on("hidden.bs.modal", function () { - div.remove(); - }); - - // wire up button handlers - div.on("click", ".modal-footer a", function (e) { - var self = this; - Ember.run(function () { - var handler = $(self).data("handler"), - cb = callbacks[handler], - hideModal = null; - - // sort of @see https://github.com/makeusabrew/bootbox/pull/68 - heavily adapted - // if we've got a custom href attribute, all bets are off - if ( - typeof handler !== "undefined" && - typeof handlers[handler]["href"] !== "undefined" - ) { - return; - } - - e.preventDefault(); - - if (typeof cb === "function") { - hideModal = cb(e); - } - - // the only way hideModal *will* be false is if a callback exists and - // returns it as a value. in those situations, don't hide the dialog - // @see https://github.com/makeusabrew/bootbox/pull/25 - if (hideModal !== false) { - div.modal("hide"); - } - }); - }); - - // stick the modal right at the bottom of the main body out of the way - (that.$body || $("body")).append(div); - - div.modal({ - // unless explicitly overridden take whatever our default backdrop value is - backdrop: - typeof options.backdrop === "undefined" - ? _backdrop - : options.backdrop, - // ignore bootstrap's keyboard options; we'll handle this ourselves (more fine-grained control) - keyboard: false, - // @ see https://github.com/makeusabrew/bootbox/issues/69 - // we *never* want the modal to be shown before we can bind stuff to it - // this method can also take a 'show' option, but we'll only use that - // later if we need to - show: false, - }); - - // @see https://github.com/makeusabrew/bootbox/issues/64 - // @see https://github.com/makeusabrew/bootbox/issues/60 - // ...caused by... - // @see https://github.com/twitter/bootstrap/issues/4781 - div.on("show", function (e) { - $(document).off("focusin.modal"); - }); - - if (typeof options.show === "undefined" || options.show === true) { - div.modal("show"); - } - - return div; - }; - - /** - * #modal is deprecated in v3; it can still be used but no guarantees are - * made - have never been truly convinced of its merit but perhaps just - * needs a tidyup and some TLC - */ - that.modal = function (/*str, label, options*/) { - var str; - var label; - var options; - - var defaultOptions = { - onEscape: null, - keyboard: true, - backdrop: _backdrop, - }; - - switch (arguments.length) { - case 1: - str = arguments[0]; - break; - case 2: - str = arguments[0]; - if (typeof arguments[1] == "object") { - options = arguments[1]; - } else { - label = arguments[1]; - } - break; - case 3: - str = arguments[0]; - label = arguments[1]; - options = arguments[2]; - break; - default: - throw new Error("Incorrect number of arguments: expected 1-3"); - } - - defaultOptions["header"] = label; - - if (typeof options == "object") { - options = $.extend(defaultOptions, options); - } else { - options = defaultOptions; - } - - return that.dialog(str, [], options); - }; - - that.hideAll = function () { - $(".bootbox").modal("hide"); - }; - - that.animate = function (animate) { - _animate = animate; - }; - - that.backdrop = function (backdrop) { - _backdrop = backdrop; - }; - - that.classes = function (classes) { - _classes = classes; - }; - - /** - * private API - */ - - /** - * standard locales. Please add more according to ISO 639-1 standard. Multiple language variants are - * unlikely to be required. If this gets too large it can be split out into separate JS files. - */ - var _locales = { - br: { - OK: "OK", - CANCEL: "Cancelar", - CONFIRM: "Sim", - }, - da: { - OK: "OK", - CANCEL: "Annuller", - CONFIRM: "Accepter", - }, - de: { - OK: "OK", - CANCEL: "Abbrechen", - CONFIRM: "Akzeptieren", - }, - en: { - OK: "OK", - CANCEL: "Cancel", - CONFIRM: "OK", - }, - es: { - OK: "OK", - CANCEL: "Cancelar", - CONFIRM: "Aceptar", - }, - fr: { - OK: "OK", - CANCEL: "Annuler", - CONFIRM: "D'accord", - }, - it: { - OK: "OK", - CANCEL: "Annulla", - CONFIRM: "Conferma", - }, - nl: { - OK: "OK", - CANCEL: "Annuleren", - CONFIRM: "Accepteren", - }, - pl: { - OK: "OK", - CANCEL: "Anuluj", - CONFIRM: "Potwierdź", - }, - ru: { - OK: "OK", - CANCEL: "Отмена", - CONFIRM: "Применить", - }, - zh_CN: { - OK: "OK", - CANCEL: "取消", - CONFIRM: "确认", - }, - zh_TW: { - OK: "OK", - CANCEL: "取消", - CONFIRM: "確認", - }, - }; - - function _translate(str, locale) { - // we assume if no target locale is probided then we should take it from current setting - if (typeof locale === "undefined") { - locale = _locale; - } - if (typeof _locales[locale][str] === "string") { - return _locales[locale][str]; - } - - // if we couldn't find a lookup then try and fallback to a default translation - - if (locale != _defaultLocale) { - return _translate(str, _defaultLocale); - } - - // if we can't do anything then bail out with whatever string was passed in - last resort - return str; - } - - return that; - })(document, jQuery); - - // @see https://github.com/makeusabrew/bootbox/issues/71 - window.bootbox = bootbox; - - __exports__.default = window.bootbox; -});