Skip to content

Commit ab0bb17

Browse files
authored
Merge pull request #1010 from Patternslib/modal-target
pat-modal: allow modal in modal
2 parents 26b403d + 1d27c08 commit ab0bb17

File tree

5 files changed

+141
-6
lines changed

5 files changed

+141
-6
lines changed

src/pat/modal/documentation.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@ This will load the page at `/status/server1`, extract the element with id `conte
1515

1616
You can customise the behaviour of modals through options in the `data-pat-modal` attribute.
1717

18-
| Property | Default value | Values | Description | Type |
19-
| ------------ | --------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
20-
| `class` | | | A class name to be applied to the modal. | String. |
21-
| `closing` |  "close-button" |  ["close-button", "outside"] | Show a "close" button for closing the modal, or let it be closed by clicking outside of the modal area. | One of the mutually exclusive available string values. |
22-
| `close-text` |  "Close" |   | Specify a custom string for the close button. | String. |
18+
| Property | Default value | Values | Description | Type |
19+
| ---------------------- | ----------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
20+
| `class` | | | A class name to be applied to the modal. | String. |
21+
| `closing` |  "close-button" |  ["close-button", "outside"] | Show a "close" button for closing the modal, or let it be closed by clicking outside of the modal area. | One of the mutually exclusive available string values. |
22+
| `close-text` |  "Close" |   | Specify a custom string for the close button. | String. |
23+
| `panel-header-content` |  `:first:not(.header)` | CSS selector or "none" | Specify a CSS selector which is used for the modal header. If set to "none" no header will be added automatically and you can provide your own. | String. |
24+
| `source` | | CSS selector | CSS selector for the injection source. If not given, the URL fragment of the ``href`` attribute from the modal trigger is used. | String. |
25+
| `target` | `#pat-modal` | CSS selector | CSS selector for the injection target. | String. |

src/pat/modal/index-modal.html

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
5+
<title>Demo page</title>
6+
<link rel="stylesheet" href="/style/common.css" type="text/css" />
7+
<script
8+
src="/bundle.min.js"
9+
type="text/javascript"
10+
charset="utf-8"
11+
></script>
12+
</head>
13+
<body>
14+
<div id="pat-modal" class="pat-modal">
15+
<h1>Example modal</h1>
16+
<div class="container">
17+
<p>
18+
Sed ut perspiciatis unde omnis iste natus error sit voluptatem
19+
accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
20+
quae ab illo inventore veritatis et quasi architecto beatae
21+
vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia
22+
voluptas sit aspernatur aut odit aut fugit, sed quia
23+
consequuntur magni dolores eos qui ratione voluptatem sequi
24+
nesciunt.
25+
</p>
26+
</div>
27+
</div>
28+
</body>
29+
</html>

src/pat/modal/index.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@
5454
Modal with a custom header</a>.
5555
</p>
5656

57+
<p>
58+
Open a
59+
<a href="#modal-in-modal"
60+
class="pat-modal">
61+
Modal which contains a link to another modal.</a>.
62+
</p>
63+
5764
<div id="modal-on-load" class="pat-modal">
5865
<h1>Modal example with auto load</h1>
5966
<article class="pat-rich">
@@ -171,5 +178,9 @@ <h1 class="custom-header">Custom header</h1>
171178
</style>
172179
</template>
173180

181+
<template id="modal-in-modal">
182+
<a href="./index-modal.html#pat-modal::element" class="pat-modal" data-pat-modal="target: #pat-modal::element">Open a modal</a>
183+
</template>
184+
174185
</body>
175186
</html>

src/pat/modal/modal.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ parser.addArgument("class");
1616
parser.addArgument("closing", ["close-button"], ["close-button", "outside"], true);
1717
parser.addArgument("close-text", "Close");
1818
parser.addArgument("panel-header-content", ":first:not(.header)");
19+
parser.addArgument("source", null); // If not given, the href should specify the source via a url fragment.
20+
parser.addArgument("target", "#pat-modal");
1921

2022
export default Base.extend({
2123
name: "modal",
@@ -42,7 +44,8 @@ export default Base.extend({
4244

4345
_init_inject1() {
4446
const opts = {
45-
target: "#pat-modal",
47+
...(this.options.source && { source: this.options.source }),
48+
target: this.options.target,
4649
class:
4750
"pat-modal" + (this.options["class"] ? " " + this.options["class"] : ""),
4851
};

src/pat/modal/modal.test.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,4 +314,93 @@ describe("pat-modal", function () {
314314
expect(spy_destroy).toHaveBeenCalledTimes(1);
315315
});
316316
});
317+
318+
it("2.1 - Allow to open a modal in a modal", async function () {
319+
document.body.innerHTML = `
320+
<a class="pat-modal"
321+
href="#modal-source"
322+
>open modal 1</a>
323+
<template id="modal-source">
324+
<a class="pat-modal"
325+
href="#modal-modal-source"
326+
data-pat-modal="
327+
target: #pat-modal::element;
328+
"
329+
>Open another modal</a>
330+
</template>
331+
<template id="modal-modal-source">
332+
<div class="pat-modal" id="pat-modal">
333+
modal in modal.
334+
</div>
335+
</template>
336+
`;
337+
const el = document.querySelector(".pat-modal");
338+
new pattern(el);
339+
await utils.timeout(1); // wait a tick for async to settle.
340+
341+
el.click();
342+
await utils.timeout(1); // wait a tick for async to settle.
343+
344+
expect(document.querySelectorAll("#pat-modal").length).toBe(1);
345+
346+
const trigger_sub = document.querySelector("#pat-modal .pat-modal");
347+
expect(trigger_sub).toBeTruthy();
348+
349+
trigger_sub.click();
350+
await utils.timeout(1); // wait a tick for async to settle.
351+
expect(document.querySelectorAll("#pat-modal").length).toBe(1);
352+
expect(document.querySelector("#pat-modal").textContent).toMatch(
353+
/modal in modal\./
354+
);
355+
});
356+
357+
it("2.2 - Allow to open a modal in a modal via ajax", async function () {
358+
document.body.innerHTML = `
359+
<a class="pat-modal"
360+
href="#modal-source"
361+
>open modal 1</a>
362+
<template id="modal-source">
363+
<a class="pat-modal"
364+
href="./modal.html"
365+
data-pat-modal="
366+
source: #pat-modal::element;
367+
target: #pat-modal::element;
368+
"
369+
>Open another modal</a>
370+
</template>
371+
`;
372+
373+
jest.spyOn($, "ajax").mockImplementation(() => deferred);
374+
answer(`
375+
<html>
376+
<body>
377+
<main>
378+
<div class="pat-modal" id="pat-modal">
379+
modal in modal.
380+
</div>
381+
</main>
382+
</body>
383+
</html>
384+
`);
385+
386+
const el = document.querySelector(".pat-modal");
387+
new pattern(el);
388+
await utils.timeout(1); // wait a tick for async to settle.
389+
390+
el.click();
391+
await utils.timeout(1); // wait a tick for async to settle.
392+
393+
expect(document.querySelectorAll("#pat-modal").length).toBe(1);
394+
395+
const trigger_sub = document.querySelector("#pat-modal .pat-modal");
396+
expect(trigger_sub).toBeTruthy();
397+
398+
trigger_sub.click();
399+
await utils.timeout(1); // wait a tick for async to settle.
400+
401+
expect(document.querySelectorAll("#pat-modal").length).toBe(1);
402+
expect(document.querySelector("#pat-modal").textContent).toMatch(
403+
/modal in modal\./
404+
);
405+
});
317406
});

0 commit comments

Comments
 (0)