Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/pat/modal/modal--implementation.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import $ from "jquery";
import Modal from "./modal--implementation";

// The tinymce link modal (pat-tinymce js/links.js) constructs the modal
// imperatively (`new Modal(...)`) and calls show() synchronously right after.
// The implementation must therefore be a constructable pattern that exposes
// its methods synchronously — not a config object grafted asynchronously by
// the thin modal.js registration module.
describe("modal implementation", function () {
let $el;
beforeEach(function () {
$el = $("<div/>").appendTo("body");
});
afterEach(function () {
$el.remove();
});

it("is constructable and exposes its methods synchronously", function () {
const modal = new Modal($el, { html: "<div>content</div>" });
expect(typeof modal.show).toBe("function");
expect(typeof modal.hide).toBe("function");
});
});
44 changes: 28 additions & 16 deletions src/pat/tinymce/js/links.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import Base from "@patternslib/patternslib/src/core/base";
import events from "@patternslib/patternslib/src/core/events";
import registry from "@patternslib/patternslib/src/core/registry";
import mockupParser from "@patternslib/patternslib/src/core/mockup-parser";
import $ from "jquery";
import _ from "underscore";

import tinymce from "tinymce/tinymce";
import "../../autotoc/autotoc";
import "../../modal/modal";
// The full modal implementation, not the thin registration module: the modal
// instance is used synchronously (show() right after construction), so its
// methods must live on the prototype. This module is only reached via the
// lazily-loaded tinymce implementation, so it stays out of the eager bundle.
import Modal from "../../modal/modal--implementation";
import ImageTemplate from "../templates/image.xml";
import LinkTemplate from "../templates/link.xml";

Expand Down Expand Up @@ -408,21 +412,29 @@ export default Base.extend({
this.dom = this.tiny.dom;
this.linkType = this.options.initialLinkType;
this.linkTypes = {};
this.modal = registry.patterns["plone-modal"].init(this.$el, {
html: this.generateModalHtml(),
content: null,
buttons: ".plone-btn",
reloadWindowOnClose: false,
templateOptions: {
classDialog: "modal-dialog modal-lg",
// Construct the implementation class directly — its static init()
// (like registry.patterns["plone-modal"].init) would instantiate the
// registered thin pattern, whose methods only appear after an async
// graft, while show() is called synchronously right after this.
// mockupParser reproduces the option parsing of the registry path.
this.modal = new Modal(
this.$el,
mockupParser.getOptions(this.$el, "plone-modal", {
html: this.generateModalHtml(),
content: null,
buttons: ".plone-btn",
reloadWindowOnClose: false,
},
actionOptions: { reloadWindowOnClose: false },
backdropOptions: {
zIndex: "1340",
closeOnClick: false,
},
});
templateOptions: {
classDialog: "modal-dialog modal-lg",
reloadWindowOnClose: false,
},
actionOptions: { reloadWindowOnClose: false },
backdropOptions: {
zIndex: "1340",
closeOnClick: false,
},
})
);
this.modal.on("shown", (e) => {
this.modalShown.apply(this, [e]);
});
Expand Down
Loading