DEV: Migrate to Ember CLI (#11932)

This encompasses a lot of work done over the last year, much of which
has already been merged into master. This is the final set of changes
required to get Ember CLI running locally for development.

From here on it will be bug fixes / enhancements.

Co-authored-by: Jarek Radosz <jradosz@gmail.com>
Co-authored-by: romanrizzi <rizziromanalejandro@gmail.com>

Co-authored-by: Jarek Radosz <jradosz@gmail.com>
Co-authored-by: romanrizzi <rizziromanalejandro@gmail.com>
This commit is contained in:
Robin Ward 2021-02-03 14:22:20 -05:00 committed by GitHub
parent 8ad5284cf7
commit 61f5d501cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 23103 additions and 1247 deletions

View File

@ -14,6 +14,7 @@ import {
import { getOwner, setDefaultOwner } from "discourse-common/lib/get-owner";
import { setApplication, setResolver } from "@ember/test-helpers";
import { setupS3CDN, setupURL } from "discourse-common/lib/get-url";
import Application from "../app";
import MessageBus from "message-bus-client";
import PreloadStore from "discourse/lib/preload-store";
import QUnit from "qunit";
@ -26,6 +27,8 @@ import { clearAppEventsCache } from "discourse/services/app-events";
import { createHelperContext } from "discourse-common/lib/helpers";
import deprecated from "discourse-common/lib/deprecated";
import { flushMap } from "discourse/models/store";
import { registerObjects } from "discourse/pre-initializers/inject-discourse-objects";
import { setupApplicationTest } from "ember-qunit";
import sinon from "sinon";
const Plugin = $.fn.modal;
@ -55,9 +58,33 @@ function AcceptanceModal(option, _relatedTarget) {
});
}
export default function setupTests(app, container) {
let app;
let started = false;
function createApplication(config, settings) {
app = Application.create(config);
setApplication(app);
setResolver(buildResolver("discourse").create({ namespace: app }));
let container = app.__registry__.container();
app.__container__ = container;
setDefaultOwner(container);
if (!started) {
app.start();
started = true;
}
app.SiteSettings = settings;
registerObjects(container, app);
return app;
}
function setupTestsCommon(application, container, config) {
application.rootElement = "#ember-testing";
application.setupForTesting();
application.injectTestHelpers();
sinon.config = {
injectIntoThis: false,
injectInto: null,
@ -69,13 +96,6 @@ export default function setupTests(app, container) {
// Stop the message bus so we don't get ajax calls
MessageBus.stop();
app.rootElement = "#ember-testing";
app.setupForTesting();
app.SiteSettings = currentSettings();
app.start();
bootbox.$body = $("#ember-testing");
$.fn.modal = AcceptanceModal;
// disable logster error reporting
if (window.Logster) {
window.Logster.enabled = false;
@ -83,6 +103,8 @@ export default function setupTests(app, container) {
window.Logster = { enabled: false };
}
$.fn.modal = AcceptanceModal;
let server;
Object.defineProperty(window, "server", {
@ -123,7 +145,14 @@ export default function setupTests(app, container) {
});
QUnit.testStart(function (ctx) {
bootbox.$body = $("#ember-testing");
let settings = resetSettings();
if (config) {
// Ember CLI testing environment
app = createApplication(config, settings);
}
server = createPretender;
server.handlers = [];
applyDefaultHandlers(server);
@ -190,10 +219,12 @@ export default function setupTests(app, container) {
$(".modal-backdrop").remove();
flushMap();
if (!setupApplicationTest) {
// ensures any event not removed is not leaking between tests
// most likely in intialisers, other places (controller, component...)
// should be fixed in code
clearAppEventsCache(getOwner(this));
}
MessageBus.unsubscribe("*");
server = null;
@ -226,7 +257,23 @@ export default function setupTests(app, container) {
// forces 0 as duration for all jquery animations
jQuery.fx.off = true;
setApplication(app);
setDefaultOwner(container);
setApplication(application);
setDefaultOwner(application.__container__);
resetSite();
}
export function setupTestsLegacy(application) {
app = application;
setResolver(buildResolver("discourse").create({ namespace: app }));
setupTestsCommon(application, app.__container__);
app.SiteSettings = currentSettings();
app.start();
}
export default function setupTests(config) {
let settings = resetSettings();
app = createApplication(config, settings);
setupTestsCommon(app, app.__container__, config);
}

View File

@ -0,0 +1,13 @@
import config from "../config/environment";
import { setEnvironment } from "discourse-common/config/environment";
import { start } from "ember-qunit";
setEnvironment("testing");
document.addEventListener("discourse-booted", () => {
let setupTests = require("discourse/tests/setup-tests").default;
Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION = false;
setupTests(config.APP);
start();
});

View File

@ -50,7 +50,5 @@ document.write(
"<style>#ember-testing-container { position: absolute; background: white; bottom: 0; right: 0; width: 640px; height: 384px; overflow: auto; z-index: 9999; border: 1px solid #ccc; } #ember-testing { zoom: 50%; }</style>"
);
let app = window.Discourse;
app.injectTestHelpers();
let setupTests = require("discourse/tests/setup-tests").default;
setupTests(app, app.__container__);
let setupTestsLegacy = require("discourse/tests/setup-tests").setupTestsLegacy;
setupTestsLegacy(window.Discourse);

View File

@ -9,10 +9,6 @@ discourseModule("Unit | Controller | avatar-selector", function (hooks) {
});
test("avatarTemplate", function (assert) {
const avatarSelectorController = this.owner.lookup(
"controller:avatar-selector"
);
const user = EmberObject.create({
avatar_template: "avatar",
system_avatar_template: "system",
@ -22,8 +18,9 @@ discourseModule("Unit | Controller | avatar-selector", function (hooks) {
gravatar_avatar_upload_id: 2,
custom_avatar_upload_id: 3,
});
avatarSelectorController.setProperties({ user });
const avatarSelectorController = this.getController("avatar-selector", {
user,
});
user.set("avatar_template", "system");
assert.equal(

View File

@ -4,8 +4,8 @@ import { test } from "qunit";
discourseModule("Unit | Controller | create-account", function () {
test("basicUsernameValidation", async function (assert) {
const testInvalidUsername = async function (username, expectedReason) {
const controller = await this.owner.lookup("controller:create-account");
const testInvalidUsername = async (username, expectedReason) => {
const controller = this.getController("create-account");
controller.set("accountUsername", username);
let validation = controller.basicUsernameValidation(username);
@ -15,7 +15,7 @@ discourseModule("Unit | Controller | create-account", function () {
expectedReason,
"username validation reason: " + username + ", " + expectedReason
);
}.bind(this);
};
testInvalidUsername("", undefined);
testInvalidUsername("x", I18n.t("user.username.too_short"));
@ -40,7 +40,7 @@ discourseModule("Unit | Controller | create-account", function () {
});
test("passwordValidation", async function (assert) {
const controller = await this.owner.lookup("controller:create-account");
const controller = this.getController("create-account");
controller.set("authProvider", "");
controller.set("accountEmail", "pork@chops.com");

View File

@ -3,7 +3,7 @@ import { test } from "qunit";
discourseModule("Unit | Controller | history", function () {
test("displayEdit", async function (assert) {
const HistoryController = this.owner.lookup("controller:history");
const HistoryController = this.getController("history");
HistoryController.setProperties({
model: { last_revision: 3, current_revision: 3, can_edit: false },

View File

@ -1,25 +1,23 @@
import EmberObject from "@ember/object";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import { test } from "qunit";
discourseModule("Unit | Controller | preferences/account", function () {
test("updating of associated accounts", function (assert) {
const controller = this.owner.lookup("controller:preferences/account");
controller.setProperties({
const controller = this.getController("preferences/account", {
siteSettings: {
enable_google_oauth2_logins: true,
},
model: EmberObject.create({
model: {
id: 70,
second_factor_enabled: true,
is_anonymous: true,
}),
currentUser: EmberObject.create({
},
currentUser: {
id: 1234,
}),
site: EmberObject.create({
},
site: {
isMobileDevice: false,
}),
},
});
assert.equal(controller.get("canUpdateAssociatedAccounts"), false);

View File

@ -3,15 +3,11 @@ import { test } from "qunit";
discourseModule("Unit | Controller | preferences/second-factor", function () {
test("displayOAuthWarning when OAuth login methods are enabled", function (assert) {
const controller = this.owner.lookup(
"controller:preferences/second-factor"
);
controller.setProperties({
const controller = this.getController("preferences/second-factor", {
siteSettings: {
enable_google_oauth2_logins: true,
},
});
assert.equal(controller.get("displayOAuthWarning"), true);
});
});

View File

@ -1,4 +1,3 @@
import EmberObject from "@ember/object";
import createStore from "discourse/tests/helpers/create-store";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import { test } from "qunit";
@ -12,11 +11,10 @@ discourseModule("Unit | Controller | reorder-categories", function () {
categories.push(store.createRecord("category", { id: i, position: 0 }));
}
const site = EmberObject.create({ categories: categories });
const reorderCategoriesController = this.owner.lookup(
"controller:reorder-categories"
const reorderCategoriesController = this.getController(
"reorder-categories",
{ site: { categories } }
);
reorderCategoriesController.setProperties({ site });
reorderCategoriesController.reorder();
reorderCategoriesController
@ -52,14 +50,11 @@ discourseModule("Unit | Controller | reorder-categories", function () {
slug: "other",
});
const categories = [child2, parent, other, child1];
const expectedOrderSlugs = ["parent", "child2", "child1", "other"];
const site = EmberObject.create({ categories: categories });
const reorderCategoriesController = this.owner.lookup(
"controller:reorder-categories"
const reorderCategoriesController = this.getController(
"reorder-categories",
{ site: { categories: [child2, parent, other, child1] } }
);
reorderCategoriesController.setProperties({ site });
reorderCategoriesController.reorder();
assert.deepEqual(
@ -89,12 +84,10 @@ discourseModule("Unit | Controller | reorder-categories", function () {
slug: "test",
});
const categories = [elem1, elem2, elem3];
const site = EmberObject.create({ categories: categories });
const reorderCategoriesController = this.owner.lookup(
"controller:reorder-categories"
const reorderCategoriesController = this.getController(
"reorder-categories",
{ site: { categories: [elem1, elem2, elem3] } }
);
reorderCategoriesController.setProperties({ site });
reorderCategoriesController.actions.change.call(
reorderCategoriesController,
@ -136,12 +129,10 @@ discourseModule("Unit | Controller | reorder-categories", function () {
slug: "test",
});
const categories = [elem1, child1, elem2, elem3];
const site = EmberObject.create({ categories: categories });
const reorderCategoriesController = this.owner.lookup(
"controller:reorder-categories"
const reorderCategoriesController = this.getController(
"reorder-categories",
{ site: { categories: [elem1, child1, elem2, elem3] } }
);
reorderCategoriesController.setProperties({ site });
reorderCategoriesController.actions.change.call(
reorderCategoriesController,
@ -190,12 +181,10 @@ discourseModule("Unit | Controller | reorder-categories", function () {
slug: "test",
});
const categories = [elem1, child1, child2, elem2, elem3];
const site = EmberObject.create({ categories: categories });
const reorderCategoriesController = this.owner.lookup(
"controller:reorder-categories"
const reorderCategoriesController = this.getController(
"reorder-categories",
{ site: { categories: [elem1, child1, child2, elem2, elem3] } }
);
reorderCategoriesController.setProperties({ site });
reorderCategoriesController.reorder();
reorderCategoriesController.actions.moveDown.call(

View File

@ -3,34 +3,37 @@ import { Placeholder } from "discourse/lib/posts-with-placeholders";
import { Promise } from "rsvp";
import Topic from "discourse/models/topic";
import User from "discourse/models/user";
import { moduleFor } from "ember-qunit";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import { next } from "@ember/runloop";
import pretender from "discourse/tests/helpers/create-pretender";
import { settled } from "@ember/test-helpers";
import { test } from "qunit";
moduleFor("controller:topic", "controller:topic", {
needs: [
"controller:composer",
"controller:application",
"service:app-events",
"service:document-title",
],
beforeEach() {
this.registry.register("service:screen-track", {}, { instantiate: false });
this.registry.injection("controller", "appEvents", "service:app-events");
},
});
function topicWithStream(streamDetails) {
let topic = Topic.create();
topic.get("postStream").setProperties(streamDetails);
return topic;
}
test("editTopic", function (assert) {
const model = Topic.create();
const controller = this.subject({ model });
discourseModule("Unit | Controller | topic", function (hooks) {
hooks.beforeEach(function () {
this.registry.register("service:screen-track", {}, { instantiate: false });
this.registry.injection("controller", "appEvents", "service:app-events");
});
hooks.afterEach(function () {
this.registry.unregister("service:screen-track");
this.registry.unregister("current-user:main");
let topic = this.container.lookup("controller:topic");
topic.setProperties({
selectedPostIds: [],
selectedPostUsername: null,
currentUser: null,
});
});
test("editTopic", function (assert) {
const model = Topic.create();
const controller = this.getController("topic", { model });
assert.not(controller.get("editingTopic"), "we are not editing by default");
controller.set("model.details.can_edit", false);
@ -60,9 +63,9 @@ test("editTopic", function (assert) {
controller.get("editingTopic"),
"cancelling edit mode reverts the property value"
);
});
});
test("deleteTopic", function (assert) {
test("deleteTopic", function (assert) {
const model = Topic.create();
let destroyed = false;
let modalDisplayed = false;
@ -70,7 +73,7 @@ test("deleteTopic", function (assert) {
destroyed = true;
return Promise.resolve();
};
const controller = this.subject({
const controller = this.getController("topic", {
model,
siteSettings: {
min_topic_views_for_delete_confirm: 5,
@ -88,11 +91,11 @@ test("deleteTopic", function (assert) {
model.set("views", 3);
controller.send("deleteTopic");
assert.ok(destroyed, "destroy not popular topic");
});
});
test("toggleMultiSelect", function (assert) {
test("toggleMultiSelect", async function (assert) {
const model = Topic.create();
const controller = this.subject({ model });
const controller = this.getController("topic", { model });
assert.not(
controller.get("multiSelect"),
@ -103,6 +106,7 @@ test("toggleMultiSelect", function (assert) {
assert.equal(controller.get("selectedPostIds.length"), 1);
controller.send("toggleMultiSelect");
await settled();
assert.ok(
controller.get("multiSelect"),
@ -118,6 +122,7 @@ test("toggleMultiSelect", function (assert) {
assert.equal(controller.get("selectedPostIds.length"), 1);
controller.send("toggleMultiSelect");
await settled();
assert.not(
controller.get("multiSelect"),
@ -128,11 +133,11 @@ test("toggleMultiSelect", function (assert) {
0,
"toggling 'multiSelect' clears 'selectedPostIds'"
);
});
});
test("selectedPosts", function (assert) {
test("selectedPosts", function (assert) {
let model = topicWithStream({ posts: [{ id: 1 }, { id: 2 }, { id: 3 }] });
const controller = this.subject({ model });
const controller = this.getController("topic", { model });
controller.set("selectedPostIds", [1, 2, 42]);
@ -145,15 +150,18 @@ test("selectedPosts", function (assert) {
controller.get("selectedPosts").some((p) => p === undefined),
"selectedPosts only contains valid post objects"
);
});
});
test("selectedAllPosts", function (assert) {
test("selectedAllPosts", function (assert) {
let model = topicWithStream({ stream: [1, 2, 3] });
const controller = this.subject({ model });
const controller = this.getController("topic", { model });
controller.set("selectedPostIds", [1, 2]);
assert.not(controller.get("selectedAllPosts"), "not all posts are selected");
assert.not(
controller.get("selectedAllPosts"),
"not all posts are selected"
);
controller.get("selectedPostIds").pushObject(3);
@ -175,9 +183,9 @@ test("selectedAllPosts", function (assert) {
controller.get("selectedAllPosts"),
"it uses the topic's post count for megatopics"
);
});
});
test("selectedPostsUsername", function (assert) {
test("selectedPostsUsername", function (assert) {
let model = topicWithStream({
posts: [
{ id: 1, username: "gary" },
@ -186,7 +194,7 @@ test("selectedPostsUsername", function (assert) {
],
stream: [1, 2, 3],
});
const controller = this.subject({ model });
const controller = this.getController("topic", { model });
const selectedPostIds = controller.get("selectedPostIds");
assert.equal(
@ -226,12 +234,12 @@ test("selectedPostsUsername", function (assert) {
undefined,
"no username when not already loaded posts are selected"
);
});
});
test("showSelectedPostsAtBottom", function (assert) {
test("showSelectedPostsAtBottom", function (assert) {
const site = EmberObject.create({ mobileView: false });
const model = Topic.create({ posts_count: 3 });
const controller = this.subject({ model, site });
const controller = this.getController("topic", { model, site });
assert.not(controller.get("showSelectedPostsAtBottom"), "false on desktop");
@ -248,9 +256,9 @@ test("showSelectedPostsAtBottom", function (assert) {
controller.get("showSelectedPostsAtBottom"),
"true when mobile and more than 3 posts"
);
});
});
test("canDeleteSelected", function (assert) {
test("canDeleteSelected", function (assert) {
const currentUser = User.create({ admin: false });
this.registry.register("current-user:main", currentUser, {
instantiate: false,
@ -264,7 +272,10 @@ test("canDeleteSelected", function (assert) {
],
stream: [1, 2, 3],
});
const controller = this.subject({ model });
const controller = this.getController("topic", {
model,
currentUser,
});
const selectedPostIds = controller.get("selectedPostIds");
assert.not(
@ -299,9 +310,9 @@ test("canDeleteSelected", function (assert) {
controller.get("canDeleteSelected"),
"true when all posts are selected and user is staff"
);
});
});
test("Can split/merge topic", function (assert) {
test("Can split/merge topic", function (assert) {
let model = topicWithStream({
posts: [
{ id: 1, post_number: 1, post_type: 1 },
@ -311,7 +322,7 @@ test("Can split/merge topic", function (assert) {
stream: [1, 2, 3],
});
model.set("details.can_move_posts", false);
const controller = this.subject({ model });
const controller = this.getController("topic", { model });
const selectedPostIds = controller.get("selectedPostIds");
assert.not(
@ -344,9 +355,9 @@ test("Can split/merge topic", function (assert) {
controller.get("canMergeTopic"),
"can merge topic when all posts are selected"
);
});
});
test("canChangeOwner", function (assert) {
test("canChangeOwner", function (assert) {
const currentUser = User.create({ admin: false });
this.registry.register("current-user:main", currentUser, {
instantiate: false,
@ -361,7 +372,10 @@ test("canChangeOwner", function (assert) {
stream: [1, 2],
});
model.set("currentUser", { admin: false });
const controller = this.subject({ model });
const controller = this.getController("topic", {
model,
currentUser,
});
const selectedPostIds = controller.get("selectedPostIds");
assert.not(
@ -386,9 +400,9 @@ test("canChangeOwner", function (assert) {
controller.get("canChangeOwner"),
"false when admin but more than 1 user"
);
});
});
test("canMergePosts", function (assert) {
test("canMergePosts", function (assert) {
let model = topicWithStream({
posts: [
{ id: 1, username: "gary", can_delete: true },
@ -398,7 +412,9 @@ test("canMergePosts", function (assert) {
],
stream: [1, 2, 3],
});
const controller = this.subject({ model });
const controller = this.getController("topic", {
model,
});
const selectedPostIds = controller.get("selectedPostIds");
assert.not(
@ -433,11 +449,11 @@ test("canMergePosts", function (assert) {
controller.get("canMergePosts"),
"true when all selected posts are deletable and by the same user"
);
});
});
test("Select/deselect all", function (assert) {
test("Select/deselect all", function (assert) {
let model = topicWithStream({ stream: [1, 2, 3] });
const controller = this.subject({ model });
const controller = this.getController("topic", { model });
assert.equal(
controller.get("selectedPostsCount"),
@ -460,10 +476,10 @@ test("Select/deselect all", function (assert) {
0,
"calling 'deselectAll' deselects all posts"
);
});
});
test("togglePostSelection", function (assert) {
const controller = this.subject();
test("togglePostSelection", function (assert) {
const controller = this.getController("topic");
const selectedPostIds = controller.get("selectedPostIds");
assert.equal(selectedPostIds[0], undefined, "no posts selected by default");
@ -483,22 +499,9 @@ test("togglePostSelection", function (assert) {
undefined,
"removes the selected post id if already selected"
);
});
});
// test("selectReplies", function(assert) {
// const controller = this.subject();
// const selectedPostIds = controller.get("selectedPostIds");
//
// assert.equal(selectedPostIds[0], undefined, "no posts selected by default");
//
// controller.send("selectReplies", { id: 42 });
//
// assert.equal(selectedPostIds[0], 42, "selected post #42");
// assert.equal(selectedPostIds[1], 45, "selected post #45");
// assert.equal(selectedPostIds[2], 100, "selected post #100");
// });
test("selectBelow", function (assert) {
test("selectBelow", function (assert) {
const site = EmberObject.create({
post_types: { small_action: 3, whisper: 4 },
});
@ -510,7 +513,7 @@ test("selectBelow", function (assert) {
{ id: 7, cooked: "", post_type: 4 },
],
});
const controller = this.subject({ site, model });
const controller = this.getController("topic", { site, model });
let selectedPostIds = controller.get("selectedPostIds");
assert.equal(selectedPostIds[0], undefined, "no posts selected by default");
@ -521,13 +524,13 @@ test("selectBelow", function (assert) {
assert.equal(selectedPostIds[1], 4, "also selected 1st post below post #3");
assert.equal(selectedPostIds[2], 5, "also selected 2nd post below post #3");
assert.equal(selectedPostIds[3], 8, "also selected 3rd post below post #3");
});
});
test("topVisibleChanged", function (assert) {
test("topVisibleChanged", function (assert) {
let model = topicWithStream({
posts: [{ id: 1 }],
});
const controller = this.subject({ model });
const controller = this.getController("topic", { model });
const placeholder = new Placeholder("post-placeholder");
assert.equal(
@ -537,9 +540,9 @@ test("topVisibleChanged", function (assert) {
null,
"it should work with a post-placehodler"
);
});
});
test("deletePost - no modal is shown if post does not have replies", function (assert) {
test("deletePost - no modal is shown if post does not have replies", function (assert) {
pretender.get("/posts/2/reply-ids.json", () => {
return [200, { "Content-Type": "application/json" }, []];
});
@ -561,7 +564,7 @@ test("deletePost - no modal is shown if post does not have replies", function (a
stream: [2, 3, 4],
posts: [post, { id: 3 }, { id: 4 }],
});
const controller = this.subject({ model, currentUser });
const controller = this.getController("topic", { model, currentUser });
const done = assert.async();
controller.send("deletePost", post);
@ -570,4 +573,5 @@ test("deletePost - no modal is shown if post does not have replies", function (a
assert.ok(destroyed, "post was destroyed");
done();
});
});
});

View File

@ -1,19 +0,0 @@
import { module, test } from "qunit";
/* global BreakString:true */
module("Unit | Utility | breakString", function () {
test("breakString", function (assert) {
const b = (s, hint) => new BreakString(s).break(hint);
assert.equal(b("hello"), "hello");
assert.equal(b("helloworld"), "helloworld");
assert.equal(b("HeMans11"), "He<wbr>&#8203;Mans<wbr>&#8203;11");
assert.equal(b("he_man"), "he_<wbr>&#8203;man");
assert.equal(b("he11111"), "he<wbr>&#8203;11111");
assert.equal(b("HRCBob"), "HRC<wbr>&#8203;Bob");
assert.equal(
b("bobmarleytoo", "Bob Marley Too"),
"bob<wbr>&#8203;marley<wbr>&#8203;too"
);
});
});

View File

@ -2,13 +2,21 @@ import {
currentUser,
discourseModule,
} from "discourse/tests/helpers/qunit-helpers";
import DocumentTitle from "discourse/services/document-title";
import AppEvents from "discourse/services/app-events";
import Session from "discourse/models/session";
import { test } from "qunit";
discourseModule("Unit | Service | document-title", function (hooks) {
hooks.beforeEach(function () {
this.documentTitle = this.container.lookup("service:document-title");
const session = Session.current();
session.hasFocus = true;
this.documentTitle = DocumentTitle.create({
session,
appEvents: AppEvents.create(),
});
this.documentTitle.currentUser = null;
this.container.lookup("session:main").hasFocus = true;
});
hooks.afterEach(function () {

View File

@ -1,12 +1,12 @@
import Component from "@ember/component";
import { afterRender } from "discourse-common/utils/decorators";
import componentTest from "discourse/tests/helpers/component-test";
import { exists } from "discourse/tests/helpers/qunit-helpers";
import { moduleForComponent } from "ember-qunit";
import componentTest, {
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import { discourseModule, exists } from "discourse/tests/helpers/qunit-helpers";
import hbs from "htmlbars-inline-precompile";
const fooComponent = Component.extend({
layoutName: "foo-component",
classNames: ["foo-component"],
baz: null,
@ -29,23 +29,25 @@ const fooComponent = Component.extend({
},
});
moduleForComponent("utils:decorators", { integration: true });
discourseModule("utils:decorators", function (hooks) {
setupRenderingTest(hooks);
componentTest("afterRender", {
template: "{{foo-component baz=baz}}",
componentTest("afterRender", {
template: hbs`{{foo-component baz=baz}}`,
beforeEach() {
this.registry.register("component:foo-component", fooComponent);
this.set("baz", 0);
},
test(assert) {
async test(assert) {
assert.ok(exists(document.querySelector(".foo-component")));
assert.equal(this.baz, 1);
this.clearRender();
await this.clearRender();
assert.ok(!exists(document.querySelector(".foo-component")));
assert.equal(this.baz, 1);
},
});
});

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
{
"private": true,
"workspaces": [
"discourse",
"admin",
"discourse-common",
"discourse-hbr",
"discourse-widget-hbs",
"pretty-text",
"select-kit"
]
}

View File

@ -15,9 +15,10 @@
"start": "ember serve"
},
"dependencies": {
"ember-auto-import": "^1.5.3",
"ember-cli-babel": "^7.13.0",
"ember-cli-htmlbars": "^4.2.0",
"ember-auto-import": "^1.5.3"
"xss": "^1.0.8"
},
"devDependencies": {
"@ember/optional-features": "^1.1.0",

View File

@ -52,7 +52,9 @@ define("@ember/test-helpers", () => {
return window[attr](...arguments);
};
});
helpers.triggerKeyEvent = window.keyEvent;
helpers.triggerKeyEvent = function () {
return window.keyEvent(...arguments);
};
return helpers;
});
define("pretender", () => {

File diff suppressed because it is too large Load Diff

View File

@ -279,9 +279,13 @@ class Compiler {
}
}
function compile(template) {
const preprocessor = Ember.__loader.require("@glimmer/syntax");
const compiled = preprocessor.preprocess(template);
const loader = typeof Ember !== "undefined" ? Ember.__loader.require : require;
function compile(template, glimmer) {
if (!glimmer) {
glimmer = loader("@glimmer/syntax");
}
const compiled = glimmer.preprocess(template);
const compiler = new Compiler(compiled);
let code = compiler.compile();
@ -305,7 +309,7 @@ function error(path, state, msg) {
);
}
exports.WidgetHbsCompiler = function (babel) {
const WidgetHbsCompiler = function (babel) {
let t = babel.types;
return {
visitor: {
@ -353,11 +357,16 @@ exports.WidgetHbsCompiler = function (babel) {
.join("");
try {
path.replaceWithSourceString(compile(template));
path.replaceWithSourceString(
compile(template, WidgetHbsCompiler.glimmer)
);
} catch (e) {
console.error("widget hbs error", e.toString());
return error(path, state, e.toString());
}
},
},
};
};
exports.WidgetHbsCompiler = WidgetHbsCompiler;

View File

@ -66,7 +66,7 @@ acceptance("Poll breakdown", function (needs) {
"shows the breakdown button when poll_groupable_user_fields is non-empty"
);
await click(".poll-show-breakdown:first");
await click(".poll-show-breakdown");
assert.equal(
queryAll(".poll-breakdown-total-votes")[0].textContent.trim(),
@ -88,10 +88,10 @@ acceptance("Poll breakdown", function (needs) {
test("Changing the display mode from percentage to count", async function (assert) {
await visit("/t/-/topic_with_pie_chart_poll");
await click(".poll-show-breakdown:first");
await click(".poll-show-breakdown");
assert.equal(
queryAll(".poll-breakdown-option-count:first")[0].textContent.trim(),
queryAll(".poll-breakdown-option-count")[0].textContent.trim(),
"40.0%",
"displays the correct vote percentage"
);
@ -99,7 +99,7 @@ acceptance("Poll breakdown", function (needs) {
await click(".modal-tabs .count");
assert.equal(
queryAll(".poll-breakdown-option-count:first")[0].textContent.trim(),
queryAll(".poll-breakdown-option-count")[0].textContent.trim(),
"2",
"displays the correct vote count"
);

View File

@ -68,15 +68,15 @@ acceptance("Rendering polls with bar charts - desktop", function (needs) {
await click("button.toggle-results");
assert.equal(
queryAll(".poll-voters:first li").length,
queryAll(".poll-voters:nth-of-type(1) li").length,
25,
"it should display the right number of voters"
);
await click(".poll-voters-toggle-expand:first a");
await click(".poll-voters-toggle-expand:nth-of-type(1) a");
assert.equal(
queryAll(".poll-voters:first li").length,
queryAll(".poll-voters:nth-of-type(1) li").length,
26,
"it should display the right number of voters"
);
@ -91,20 +91,20 @@ acceptance("Rendering polls with bar charts - desktop", function (needs) {
await click("button.toggle-results");
assert.equal(
queryAll(".poll-voters:first li").length,
queryAll(".poll-voters:nth-of-type(1) li").length,
25,
"it should display the right number of voters"
);
assert.notOk(
queryAll(".poll-voters:first li:first a").attr("href"),
queryAll(".poll-voters:nth-of-type(1) li:nth-of-type(1) a").attr("href"),
"user URL does not exist"
);
await click(".poll-voters-toggle-expand:first a");
await click(".poll-voters-toggle-expand:nth-of-type(1) a");
assert.equal(
queryAll(".poll-voters:first li").length,
queryAll(".poll-voters:nth-of-type(1) li").length,
30,
"it should display the right number of voters"
);

View File

@ -30,20 +30,20 @@ acceptance("Rendering polls with bar charts - mobile", function (needs) {
await click("button.toggle-results");
assert.equal(
queryAll(".poll-voters:first li").length,
queryAll(".poll-voters:nth-of-type(1) li").length,
25,
"it should display the right number of voters"
);
assert.notOk(
queryAll(".poll-voters:first li:first a").attr("href"),
queryAll(".poll-voters:nth-of-type(1) li:nth-of-type(1) a").attr("href"),
"user URL does not exist"
);
await click(".poll-voters-toggle-expand:first a");
await click(".poll-voters-toggle-expand:nth-of-type(1) a");
assert.equal(
queryAll(".poll-voters:first li").length,
queryAll(".poll-voters:nth-of-type(1) li").length,
35,
"it should display the right number of voters"
);

View File

@ -3,36 +3,37 @@
*
* http://bootboxjs.com/license.txt
*/
var bootbox = window.bootbox || (function(document, $) {
var bootbox =
window.bootbox ||
(function (document, $) {
/*jshint scripturl:true sub:true */
var _locale = 'en',
_defaultLocale = 'en',
var _locale = "en",
_defaultLocale = "en",
_animate = true,
_backdrop = 'static',
_defaultHref = 'javascript:;',
_classes = '',
_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) {
that.setLocale = function (locale) {
for (var i in _locales) {
if (i == locale) {
_locale = locale;
return;
}
}
throw new Error('Invalid locale: '+locale);
throw new Error("Invalid locale: " + locale);
};
that.addLocale = function(locale, translations) {
if (typeof _locales[locale] === 'undefined') {
that.addLocale = function (locale, translations) {
if (typeof _locales[locale] === "undefined") {
_locales[locale] = {};
}
for (var str in translations) {
@ -40,23 +41,23 @@ var bootbox = window.bootbox || (function(document, $) {
}
};
that.setIcons = function(icons) {
that.setIcons = function (icons) {
_icons = icons;
if (typeof _icons !== 'object' || _icons === null) {
if (typeof _icons !== "object" || _icons === null) {
_icons = {};
}
};
that.setBtnClasses = function(btnClasses) {
that.setBtnClasses = function (btnClasses) {
_btnClasses = btnClasses;
if (typeof _btnClasses !== 'object' || _btnClasses === null) {
if (typeof _btnClasses !== "object" || _btnClasses === null) {
_btnClasses = {};
}
};
that.alert = function(/*str, label, cb*/) {
that.alert = function (/*str, label, cb*/) {
var str = "",
label = _translate('OK'),
label = _translate("OK"),
cb = null;
switch (arguments.length) {
@ -67,7 +68,7 @@ var bootbox = window.bootbox || (function(document, $) {
case 2:
// callback *or* custom button label dependent on type
str = arguments[0];
if (typeof arguments[1] == 'function') {
if (typeof arguments[1] == "function") {
cb = arguments[1];
} else {
label = arguments[1];
@ -83,23 +84,27 @@ var bootbox = window.bootbox || (function(document, $) {
throw new Error("Incorrect number of arguments: expected 1-3");
}
return that.dialog(str, {
return that.dialog(
str,
{
// only button (ok)
"label" : label,
"icon" : _icons.OK,
"class" : _btnClasses.OK,
"callback": cb
}, {
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
});
onEscape: cb || true,
}
);
};
that.confirm = function(/*str, labelCancel, labelOk, cb*/) {
that.confirm = function (/*str, labelCancel, labelOk, cb*/) {
var str = "",
labelCancel = _translate('CANCEL'),
labelOk = _translate('CONFIRM'),
labelCancel = _translate("CANCEL"),
labelOk = _translate("CONFIRM"),
cb = null;
switch (arguments.length) {
@ -108,7 +113,7 @@ var bootbox = window.bootbox || (function(document, $) {
break;
case 2:
str = arguments[0];
if (typeof arguments[1] == 'function') {
if (typeof arguments[1] == "function") {
cb = arguments[1];
} else {
labelCancel = arguments[1];
@ -117,7 +122,7 @@ var bootbox = window.bootbox || (function(document, $) {
case 3:
str = arguments[0];
labelCancel = arguments[1];
if (typeof arguments[2] == 'function') {
if (typeof arguments[2] == "function") {
cb = arguments[2];
} else {
labelOk = arguments[2];
@ -133,40 +138,47 @@ var bootbox = window.bootbox || (function(document, $) {
throw new Error("Incorrect number of arguments: expected 1-4");
}
var cancelCallback = function() {
if (typeof cb === 'function') {
var cancelCallback = function () {
if (typeof cb === "function") {
return cb(false);
}
};
var confirmCallback = function() {
if (typeof cb === 'function') {
var confirmCallback = function () {
if (typeof cb === "function") {
return cb(true);
}
};
return that.dialog(str, [{
return that.dialog(
str,
[
{
// first button (cancel)
"label" : labelCancel,
"icon" : _icons.CANCEL,
"class" : _btnClasses.CANCEL,
"callback": cancelCallback
}, {
label: labelCancel,
icon: _icons.CANCEL,
class: _btnClasses.CANCEL,
callback: cancelCallback,
},
{
// second button (confirm)
"label" : labelOk,
"icon" : _icons.CONFIRM,
"class" : _btnClasses.CONFIRM,
"callback": confirmCallback
}], {
label: labelOk,
icon: _icons.CONFIRM,
class: _btnClasses.CONFIRM,
callback: confirmCallback,
},
],
{
// escape key bindings
"onEscape": cancelCallback
});
onEscape: cancelCallback,
}
);
};
that.prompt = function(/*str, labelCancel, labelOk, cb, defaultVal*/) {
that.prompt = function (/*str, labelCancel, labelOk, cb, defaultVal*/) {
var str = "",
labelCancel = _translate('CANCEL'),
labelOk = _translate('CONFIRM'),
labelCancel = _translate("CANCEL"),
labelOk = _translate("CONFIRM"),
cb = null,
defaultVal = "";
@ -176,7 +188,7 @@ var bootbox = window.bootbox || (function(document, $) {
break;
case 2:
str = arguments[0];
if (typeof arguments[1] == 'function') {
if (typeof arguments[1] == "function") {
cb = arguments[1];
} else {
labelCancel = arguments[1];
@ -185,7 +197,7 @@ var bootbox = window.bootbox || (function(document, $) {
case 3:
str = arguments[0];
labelCancel = arguments[1];
if (typeof arguments[2] == 'function') {
if (typeof arguments[2] == "function") {
cb = arguments[2];
} else {
labelOk = arguments[2];
@ -212,53 +224,64 @@ var bootbox = window.bootbox || (function(document, $) {
// let's keep a reference to the form object for later
var form = $("<form></form>");
form.append("<input class='input-block-level' autocomplete=off type=text value='" + defaultVal + "' />");
form.append(
"<input class='input-block-level' autocomplete=off type=text value='" +
defaultVal +
"' />"
);
var cancelCallback = function() {
if (typeof cb === 'function') {
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') {
var confirmCallback = function () {
if (typeof cb === "function") {
return cb(form.find("input[type=text]").val());
}
};
var div = that.dialog(form, [{
var div = that.dialog(
form,
[
{
// first button (cancel)
"label" : labelCancel,
"icon" : _icons.CANCEL,
"class" : _btnClasses.CANCEL,
"callback": cancelCallback
}, {
label: labelCancel,
icon: _icons.CANCEL,
class: _btnClasses.CANCEL,
callback: cancelCallback,
},
{
// second button (confirm)
"label" : labelOk,
"icon" : _icons.CONFIRM,
"class" : _btnClasses.CONFIRM,
"callback": confirmCallback
}], {
label: labelOk,
icon: _icons.CONFIRM,
class: _btnClasses.CONFIRM,
callback: confirmCallback,
},
],
{
// prompts need a few extra options
"header" : header,
header: header,
// explicitly tell dialog NOT to show the dialog...
"show" : false,
"onEscape": cancelCallback
});
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() {
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) {
form.on("submit", function (e) {
e.preventDefault();
div.find(".btn-primary").click();
});
@ -269,7 +292,7 @@ var bootbox = window.bootbox || (function(document, $) {
return div;
};
that.dialog = function(str, handlers, options) {
that.dialog = function (str, handlers, options) {
var buttons = "",
callbacks = [];
@ -278,9 +301,9 @@ var bootbox = window.bootbox || (function(document, $) {
}
// check for single object and convert to array if necessary
if (typeof handlers === 'undefined') {
if (typeof handlers === "undefined") {
handlers = [];
} else if (typeof handlers.length == 'undefined') {
} else if (typeof handlers.length == "undefined") {
handlers = [handlers];
}
@ -288,13 +311,15 @@ var bootbox = window.bootbox || (function(document, $) {
while (i--) {
var label = null,
href = null,
_class = 'btn-default',
icon = '',
_class = "btn-default",
icon = "",
callback = null;
if (typeof handlers[i]['label'] == 'undefined' &&
typeof handlers[i]['class'] == 'undefined' &&
typeof handlers[i]['callback'] == 'undefined') {
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
@ -309,48 +334,59 @@ var bootbox = window.bootbox || (function(document, $) {
}
}
if (propCount == 1 && typeof handlers[i][j] == 'function') {
if (propCount == 1 && typeof handlers[i][j] == "function") {
// matches condensed format of label -> function
handlers[i]['label'] = property;
handlers[i]['callback'] = handlers[i][j];
handlers[i]["label"] = property;
handlers[i]["callback"] = handlers[i][j];
}
}
if (typeof handlers[i]['callback']== 'function') {
callback = handlers[i]['callback'];
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) {
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';
_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]["link"] !== true) {
_class = "btn " + _class;
}
if (handlers[i]['label']) {
label = handlers[i]['label'];
if (handlers[i]["label"]) {
label = handlers[i]["label"];
} else {
label = "Option "+(i+1);
label = "Option " + (i + 1);
}
if (handlers[i]['icon']) {
icon = handlers[i]['icon'];
if (handlers[i]["icon"]) {
icon = handlers[i]["icon"];
}
if (handlers[i]['href']) {
href = handlers[i]['href'];
}
else {
if (handlers[i]["href"]) {
href = handlers[i]["href"];
} else {
href = _defaultHref;
}
buttons = buttons + "<a data-handler='"+i+"' class='"+_class+"' href='" + href + "'>"+icon+"<span class='d-button-label'>"+label+"</span></a>";
buttons =
buttons +
"<a data-handler='" +
i +
"' class='" +
_class +
"' href='" +
href +
"'>" +
icon +
"<span class='d-button-label'>" +
label +
"</span></a>";
callbacks[i] = callback;
}
@ -361,22 +397,34 @@ var bootbox = window.bootbox || (function(document, $) {
// @see https://github.com/twitter/bootstrap/issues/4854
// for an explanation of tabIndex=-1
var parts = ["<div class='bootbox modal' tabindex='-1' style='overflow:hidden;'>"];
var parts = [
"<div class='bootbox modal' tabindex='-1' style='overflow:hidden;'>",
];
if (options['header']) {
var closeButton = '';
if (typeof options['headerCloseButton'] == 'undefined' || options['headerCloseButton']) {
closeButton = "<a href='"+_defaultHref+"' class='close'>&times;</a>";
if (options["header"]) {
var closeButton = "";
if (
typeof options["headerCloseButton"] == "undefined" ||
options["headerCloseButton"]
) {
closeButton =
"<a href='" + _defaultHref + "' class='close'>&times;</a>";
}
parts.push("<div class='modal-header'>"+closeButton+"<h3>"+options['header']+"</h3></div>");
parts.push(
"<div class='modal-header'>" +
closeButton +
"<h3>" +
options["header"] +
"</h3></div>"
);
}
// push an empty body into which we'll inject the proper content later
parts.push("<div class='modal-body'></div>");
if (buttons) {
parts.push("<div class='modal-footer'>"+buttons+"</div>");
parts.push("<div class='modal-footer'>" + buttons + "</div>");
}
parts.push("</div>");
@ -384,13 +432,15 @@ var bootbox = window.bootbox || (function(document, $) {
var div = $(parts.join("\n"));
// check whether we should fade in/out
var shouldFade = (typeof options.animate === 'undefined') ? _animate : options.animate;
var shouldFade =
typeof options.animate === "undefined" ? _animate : options.animate;
if (shouldFade) {
div.addClass("fade");
}
var optionalClasses = (typeof options.classes === 'undefined') ? _classes : options.classes;
var optionalClasses =
typeof options.classes === "undefined" ? _classes : options.classes;
if (optionalClasses) {
div.addClass(optionalClasses);
}
@ -401,60 +451,60 @@ var bootbox = window.bootbox || (function(document, $) {
function onCancel(source) {
// for now source is unused, but it will be in future
var hideModal = null;
if (typeof options.onEscape === 'function') {
if (typeof options.onEscape === "function") {
// @see https://github.com/makeusabrew/bootbox/issues/91
hideModal = options.onEscape();
}
if (hideModal !== false) {
div.modal('hide');
div.modal("hide");
}
}
// hook into the modal's keyup trigger to check for the escape key
div.on('keyup.dismiss.modal', function(e) {
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');
onCancel("escape");
}
});
// handle close buttons too
div.on('click', 'a.close', function(e) {
div.on("click", "a.close", function (e) {
e.preventDefault();
onCancel('close');
onCancel("close");
});
// well, *if* we have a primary - give the first dom element focus
div.on('shown.bs.modal', function() {
div.on("shown.bs.modal", function () {
div.find("a.btn-primary:first").focus();
});
div.on('hidden.bs.modal', function() {
div.on("hidden.bs.modal", function () {
div.remove();
});
// wire up button handlers
div.on('click', '.modal-footer a', function(e) {
div.on("click", ".modal-footer a", function (e) {
var self = this;
Ember.run(function() {
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') {
if (
typeof handler !== "undefined" &&
typeof handlers[handler]["href"] !== "undefined"
) {
return;
}
e.preventDefault();
if (typeof cb === 'function') {
if (typeof cb === "function") {
hideModal = cb(e);
}
@ -472,25 +522,28 @@ var bootbox = window.bootbox || (function(document, $) {
div.modal({
// unless explicitly overridden take whatever our default backdrop value is
backdrop : (typeof options.backdrop === 'undefined') ? _backdrop : options.backdrop,
backdrop:
typeof options.backdrop === "undefined"
? _backdrop
: options.backdrop,
// ignore bootstrap's keyboard options; we'll handle this ourselves (more fine-grained control)
keyboard : false,
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
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) {
div.on("show", function (e) {
$(document).off("focusin.modal");
});
if (typeof options.show === 'undefined' || options.show === true) {
if (typeof options.show === "undefined" || options.show === true) {
div.modal("show");
}
@ -502,15 +555,15 @@ var bootbox = window.bootbox || (function(document, $) {
* made - have never been truly convinced of its merit but perhaps just
* needs a tidyup and some TLC
*/
that.modal = function(/*str, label, options*/) {
that.modal = function (/*str, label, options*/) {
var str;
var label;
var options;
var defaultOptions = {
"onEscape": null,
"keyboard": true,
"backdrop": _backdrop
onEscape: null,
keyboard: true,
backdrop: _backdrop,
};
switch (arguments.length) {
@ -519,7 +572,7 @@ var bootbox = window.bootbox || (function(document, $) {
break;
case 2:
str = arguments[0];
if (typeof arguments[1] == 'object') {
if (typeof arguments[1] == "object") {
options = arguments[1];
} else {
label = arguments[1];
@ -534,9 +587,9 @@ var bootbox = window.bootbox || (function(document, $) {
throw new Error("Incorrect number of arguments: expected 1-3");
}
defaultOptions['header'] = label;
defaultOptions["header"] = label;
if (typeof options == 'object') {
if (typeof options == "object") {
options = $.extend(defaultOptions, options);
} else {
options = defaultOptions;
@ -545,20 +598,19 @@ var bootbox = window.bootbox || (function(document, $) {
return that.dialog(str, [], options);
};
that.hideAll = function() {
that.hideAll = function () {
$(".bootbox").modal("hide");
};
that.animate = function(animate) {
that.animate = function (animate) {
_animate = animate;
};
that.backdrop = function(backdrop) {
that.backdrop = function (backdrop) {
_backdrop = backdrop;
};
that.classes = function(classes) {
that.classes = function (classes) {
_classes = classes;
};
@ -571,74 +623,74 @@ var bootbox = window.bootbox || (function(document, $) {
* 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'
br: {
OK: "OK",
CANCEL: "Cancelar",
CONFIRM: "Sim",
},
'da' : {
OK : 'OK',
CANCEL : 'Annuller',
CONFIRM : 'Accepter'
da: {
OK: "OK",
CANCEL: "Annuller",
CONFIRM: "Accepter",
},
'de' : {
OK : 'OK',
CANCEL : 'Abbrechen',
CONFIRM : 'Akzeptieren'
de: {
OK: "OK",
CANCEL: "Abbrechen",
CONFIRM: "Akzeptieren",
},
'en' : {
OK : 'OK',
CANCEL : 'Cancel',
CONFIRM : 'OK'
en: {
OK: "OK",
CANCEL: "Cancel",
CONFIRM: "OK",
},
'es' : {
OK : 'OK',
CANCEL : 'Cancelar',
CONFIRM : 'Aceptar'
es: {
OK: "OK",
CANCEL: "Cancelar",
CONFIRM: "Aceptar",
},
'fr' : {
OK : 'OK',
CANCEL : 'Annuler',
CONFIRM : 'D\'accord'
fr: {
OK: "OK",
CANCEL: "Annuler",
CONFIRM: "D'accord",
},
'it' : {
OK : 'OK',
CANCEL : 'Annulla',
CONFIRM : 'Conferma'
it: {
OK: "OK",
CANCEL: "Annulla",
CONFIRM: "Conferma",
},
'nl' : {
OK : 'OK',
CANCEL : 'Annuleren',
CONFIRM : 'Accepteren'
nl: {
OK: "OK",
CANCEL: "Annuleren",
CONFIRM: "Accepteren",
},
'pl' : {
OK : 'OK',
CANCEL : 'Anuluj',
CONFIRM : 'Potwierdź'
pl: {
OK: "OK",
CANCEL: "Anuluj",
CONFIRM: "Potwierdź",
},
'ru' : {
OK : 'OK',
CANCEL : 'Отмена',
CONFIRM : 'Применить'
ru: {
OK: "OK",
CANCEL: "Отмена",
CONFIRM: "Применить",
},
'zh_CN' : {
OK : 'OK',
CANCEL : '取消',
CONFIRM : '确认'
zh_CN: {
OK: "OK",
CANCEL: "取消",
CONFIRM: "确认",
},
zh_TW: {
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') {
if (typeof locale === "undefined") {
locale = _locale;
}
if (typeof _locales[locale][str] === 'string') {
if (typeof _locales[locale][str] === "string") {
return _locales[locale][str];
}
@ -653,8 +705,11 @@ var bootbox = window.bootbox || (function(document, $) {
}
return that;
}(document, window.jQuery));
})(document, window.jQuery);
// @see https://github.com/makeusabrew/bootbox/issues/71
window.bootbox = bootbox;
define("bootbox", ["exports"], function (__exports__) {
__exports__.default = window.bootbox;
});

View File

@ -2494,12 +2494,7 @@ pretender@^1.6:
fake-xml-http-request "^1.6.0"
route-recognizer "^0.3.3"
prettier@2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5"
integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==
prettier@^2.0.4:
prettier@2.2.1, prettier@^2.0.4:
version "2.2.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5"
integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==