Skip to content

Commit 46ba4df

Browse files
authored
Merge pull request #1089 from Patternslib/thet-optimizations
Bundle generation optimizations
2 parents 1cb91d7 + c34d4a0 commit 46ba4df

File tree

9 files changed

+298
-214
lines changed

9 files changed

+298
-214
lines changed

src/core/basepattern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class BasePattern {
6969
}, 0);
7070
}
7171

72-
init() {
72+
async init() {
7373
// Extend this method in your pattern.
7474
}
7575

src/core/dom.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,21 @@ const is_visible = (el) => {
9292
return el.offsetWidth > 0 && el.offsetHeight > 0;
9393
};
9494

95+
/**
96+
* Test, if a element is a input-type element.
97+
*
98+
* This is taken from Sizzle/jQuery at:
99+
* https://github.com/jquery/sizzle/blob/f2a2412e5e8a5d9edf168ae3b6633ac8e6bd9f2e/src/sizzle.js#L139
100+
* https://github.com/jquery/sizzle/blob/f2a2412e5e8a5d9edf168ae3b6633ac8e6bd9f2e/src/sizzle.js#L1773
101+
*
102+
* @param {Node} el - The DOM node to test.
103+
* @returns {Boolean} - True if the element is a input-type element.
104+
*/
105+
const is_input = (el) => {
106+
const re_input = /^(?:input|select|textarea|button)$/i;
107+
return re_input.test(el.nodeName);
108+
};
109+
95110
/**
96111
* Return all direct parents of ``el`` matching ``selector``.
97112
* This matches against all parents but not the element itself.
@@ -322,6 +337,7 @@ const dom = {
322337
get_parents: get_parents,
323338
acquire_attribute: acquire_attribute,
324339
is_visible: is_visible,
340+
is_input: is_input,
325341
create_from_string: create_from_string,
326342
get_css_value: get_css_value,
327343
find_scroll_container: find_scroll_container,

src/core/dom.test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,20 @@ describe("core.dom tests", () => {
444444
});
445445
});
446446

447+
describe("is_input", () => {
448+
it("checks, if an element is of type input or not.", (done) => {
449+
expect(dom.is_input(document.createElement("input"))).toBe(true);
450+
expect(dom.is_input(document.createElement("select"))).toBe(true);
451+
expect(dom.is_input(document.createElement("textarea"))).toBe(true);
452+
expect(dom.is_input(document.createElement("button"))).toBe(true);
453+
454+
expect(dom.is_input(document.createElement("form"))).toBe(false);
455+
expect(dom.is_input(document.createElement("div"))).toBe(false);
456+
457+
done();
458+
});
459+
});
460+
447461
describe("create_from_string", () => {
448462
it("Creates a DOM element from a string", (done) => {
449463
const res = dom.create_from_string(`

src/pat/markdown/markdown.js

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,55 @@
11
import $ from "jquery";
2+
import { BasePattern } from "../../core/basepattern";
3+
import dom from "../../core/dom";
4+
import events from "../../core/events";
25
import logging from "../../core/logging";
6+
import registry from "../../core/registry";
37
import utils from "../../core/utils";
4-
import Base from "../../core/base";
5-
import events from "../../core/events";
6-
import inject from "../inject/inject";
78

89
const log = logging.getLogger("pat.markdown");
910
const is_markdown_resource = /\.md$/;
1011

11-
const Markdown = Base.extend({
12-
name: "markdown",
13-
trigger: ".pat-markdown",
12+
class Pattern extends BasePattern {
13+
static name = "markdown";
14+
static trigger = ".pat-markdown";
1415

1516
async init() {
16-
if (this.$el.is(this.trigger)) {
17+
if (this.el.matches(this.trigger)) {
1718
/* This pattern can either be used standalone or as an enhancement
1819
* to pat-inject. The following only applies to standalone, when
19-
* $el is explicitly configured with the pat-markdown trigger.
20+
* the element is explicitly configured with the pat-markdown
21+
* trigger.
2022
*/
21-
const source = this.$el.is(":input")
22-
? this.$el.val()
23-
: this.$el[0].innerHTML;
24-
let rendered = await this.render(source);
23+
const source = dom.is_input(this.el) ? this.el.value : this.el.innerHTML;
24+
const rendered = await this.render(source);
2525
this.el.replaceWith(...rendered);
2626
}
27-
},
27+
}
2828

2929
async render(text) {
3030
const marked = (await import("marked")).marked;
3131
const DOMPurify = (await import("dompurify")).default;
32-
const SyntaxHighlight = (await import("../syntax-highlight/syntax-highlight")).default; // prettier-ignore
3332

3433
const wrapper = document.createElement("div");
3534
const parsed = DOMPurify.sanitize(marked.parse(text));
3635
wrapper.innerHTML = parsed;
37-
for (const item of wrapper.querySelectorAll("pre > code")) {
38-
const pre = item.parentElement;
39-
pre.classList.add("pat-syntax-highlight");
40-
// If the code block language was set in a fenced code block,
41-
// marked has already set the language as a class on the code tag.
42-
// pat-syntax-highlight will understand this.
43-
new SyntaxHighlight(pre);
44-
await events.await_event(pre, "init.syntax-highlight.patterns");
36+
37+
// If pat-syntax-highlight is available, highlight code blocks.
38+
const SyntaxHighlight = registry.patterns["syntax-highlight"];
39+
if (SyntaxHighlight) {
40+
for (const item of wrapper.querySelectorAll("pre > code")) {
41+
const pre = item.parentElement;
42+
pre.classList.add("pat-syntax-highlight");
43+
// If the code block language was set in a fenced code block,
44+
// marked has already set the language as a class on the code tag.
45+
// pat-syntax-highlight will understand this.
46+
new SyntaxHighlight(pre);
47+
await events.await_event(pre, "init.syntax-highlight.patterns");
48+
}
4549
}
50+
4651
return $(wrapper);
47-
},
52+
}
4853

4954
async renderForInjection(cfg, data) {
5055
let header;
@@ -59,7 +64,7 @@ const Markdown = Base.extend({
5964
}
6065
const rendered = await this.render(source);
6166
return rendered.attr("data-src", cfg.source ? cfg.url + cfg.source : cfg.url);
62-
},
67+
}
6368

6469
extractSection(text, header) {
6570
let pattern;
@@ -96,8 +101,8 @@ const Markdown = Base.extend({
96101
log.error("Failed to find section with known present header?");
97102
}
98103
return match !== null ? match[0] : null;
99-
},
100-
});
104+
}
105+
}
101106

102107
$(document).ready(function () {
103108
$(document.body).on(
@@ -117,16 +122,26 @@ $(document).ready(function () {
117122
);
118123
});
119124

120-
inject.registerTypeHandler("markdown", {
121-
async sources(cfgs, data) {
122-
return await Promise.all(
123-
cfgs.map(async function (cfg) {
124-
const pat = new Markdown(cfg.$target[0]);
125-
const rendered = await pat.renderForInjection(cfg, data);
126-
return rendered;
127-
})
128-
);
129-
},
130-
});
125+
async function register_external_handlers() {
126+
await utils.timeout(1);
127+
128+
const inject = registry.patterns.inject;
129+
if (inject) {
130+
inject.registerTypeHandler("markdown", {
131+
async sources(cfgs, data) {
132+
return await Promise.all(
133+
cfgs.map(async function (cfg) {
134+
const pat = new Pattern(cfg.$target[0]);
135+
const rendered = await pat.renderForInjection(cfg, data);
136+
return rendered;
137+
})
138+
);
139+
},
140+
});
141+
}
142+
}
143+
register_external_handlers();
131144

132-
export default Markdown;
145+
registry.register(Pattern);
146+
export default Pattern;
147+
export { Pattern };

src/pat/markdown/markdown.test.js

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import $ from "jquery";
2-
import pattern from "./markdown";
3-
import utils from "../../core/utils";
2+
import events from "../../core/events";
3+
import Pattern from "./markdown";
44
import { jest } from "@jest/globals";
55

66
describe("pat-markdown", function () {
@@ -19,77 +19,85 @@ describe("pat-markdown", function () {
1919
it("Replaces the DOM element with the rendered Markdown content.", async function () {
2020
var $el = $('<p class="pat-markdown"></p>');
2121
$el.appendTo("#lab");
22-
jest.spyOn(pattern.prototype, "render").mockImplementation(() => {
22+
jest.spyOn(Pattern.prototype, "render").mockImplementation(() => {
2323
return $("<p>Rendering</p>");
2424
});
25-
pattern.init($el);
26-
await utils.timeout(1); // wait a tick for async to settle.
25+
26+
const instance = new Pattern($el);
27+
await events.await_pattern_init(instance);
28+
2729
expect($("#lab").html()).toBe("<p>Rendering</p>");
2830
});
2931

30-
it("It does not render when the DOM element doesn't have the pattern trigger", function () {
32+
it("It does not render when the DOM element doesn't have the pattern trigger", async function () {
3133
var $el = $("<p></p>");
3234
$el.appendTo("#lab");
33-
jest.spyOn(pattern.prototype, "render").mockImplementation(() => {
35+
jest.spyOn(Pattern.prototype, "render").mockImplementation(() => {
3436
return $("<p>Rendering</p>");
3537
});
36-
pattern.init($el);
38+
const instance = new Pattern($el);
39+
await events.await_pattern_init(instance);
40+
3741
expect($("#lab").html()).toBe("<p></p>");
3842
});
3943

40-
it("uses content for non-input elements", function () {
44+
it("uses content for non-input elements", async function () {
4145
var $el = $('<p class="pat-markdown"/>').text("This is markdown");
4246
$el.appendTo("#lab");
4347
const spy_render = jest
44-
.spyOn(pattern.prototype, "render")
48+
.spyOn(Pattern.prototype, "render")
4549
.mockImplementation(() => {
4650
return $("<p/>");
4751
});
48-
pattern.init($el);
52+
const instance = new Pattern($el);
53+
await events.await_pattern_init(instance);
54+
4955
expect(spy_render).toHaveBeenCalledWith("This is markdown");
5056
});
5157

52-
it("uses value for input elements", function () {
58+
it("uses value for input elements", async function () {
5359
var $el = $('<textarea class="pat-markdown"/>').val("This is markdown");
5460
$el.appendTo("#lab");
5561
const spy_render = jest
56-
.spyOn(pattern.prototype, "render")
62+
.spyOn(Pattern.prototype, "render")
5763
.mockImplementation(() => {
5864
return $("<p/>");
5965
});
60-
pattern.init($el);
66+
const instance = new Pattern($el);
67+
await events.await_pattern_init(instance);
68+
6169
expect(spy_render).toHaveBeenCalledWith("This is markdown");
6270
});
6371
});
6472

6573
describe("when rendering", function () {
6674
it("wraps rendering in a div", async function () {
67-
const $rendering = await pattern.prototype.render("*This is markdown*");
75+
const $rendering = await Pattern.prototype.render("*This is markdown*");
6876
expect($rendering[0].tagName).toBe("DIV");
6977
});
7078

7179
it("converts markdown into HTML", async function () {
72-
const $rendering = await pattern.prototype.render("*This is markdown*");
80+
const $rendering = await Pattern.prototype.render("*This is markdown*");
7381
expect($rendering.html()).toBe(`<p><em>This is markdown</em></p>\n`);
7482
});
7583
});
7684

7785
describe("Session extraction", function () {
7886
it("Unknown section", function () {
7987
expect(
80-
pattern.prototype.extractSection("## My title\n\nContent", "Other title")
88+
Pattern.prototype.extractSection("## My title\n\nContent", "Other title")
8189
).toBe(null);
8290
});
8391

8492
it("Last hash-section", function () {
8593
expect(
86-
pattern.prototype.extractSection("## My title\n\nContent", "My title")
94+
Pattern.prototype.extractSection("## My title\n\nContent", "My title")
8795
).toBe("## My title\n\nContent");
8896
});
8997

9098
it("Hash-section with following section at same level ", function () {
9199
expect(
92-
pattern.prototype.extractSection(
100+
Pattern.prototype.extractSection(
93101
"## My title\n\nContent\n## Next section\n",
94102
"My title"
95103
)
@@ -98,7 +106,7 @@ describe("pat-markdown", function () {
98106

99107
it("Hash-section with following section at lower level ", function () {
100108
expect(
101-
pattern.prototype.extractSection(
109+
Pattern.prototype.extractSection(
102110
"## My title\n\nContent\n### Next section\n",
103111
"My title"
104112
)
@@ -107,7 +115,7 @@ describe("pat-markdown", function () {
107115

108116
it("Double underscore section", function () {
109117
expect(
110-
pattern.prototype.extractSection(
118+
Pattern.prototype.extractSection(
111119
"My title\n=======\nContent",
112120
"My title"
113121
)
@@ -116,7 +124,7 @@ describe("pat-markdown", function () {
116124

117125
it("Double underscore section with following section at same level", function () {
118126
expect(
119-
pattern.prototype.extractSection(
127+
Pattern.prototype.extractSection(
120128
"My title\n=======\nContent\n\nNext\n====\n",
121129
"My title"
122130
)
@@ -125,7 +133,7 @@ describe("pat-markdown", function () {
125133

126134
it("Double underscore section with following section at lower level", function () {
127135
expect(
128-
pattern.prototype.extractSection(
136+
Pattern.prototype.extractSection(
129137
"My title\n=======\nContent\n\nNext\n----\n",
130138
"My title"
131139
)
@@ -134,7 +142,7 @@ describe("pat-markdown", function () {
134142

135143
it("Single underscore section", function () {
136144
expect(
137-
pattern.prototype.extractSection(
145+
Pattern.prototype.extractSection(
138146
"My title\n-------\nContent",
139147
"My title"
140148
)
@@ -143,7 +151,7 @@ describe("pat-markdown", function () {
143151

144152
it("Single underscore section with following section at same level", function () {
145153
expect(
146-
pattern.prototype.extractSection(
154+
Pattern.prototype.extractSection(
147155
"My title\n-------\nContent\n\nNext\n----\n",
148156
"My title"
149157
)
@@ -152,7 +160,7 @@ describe("pat-markdown", function () {
152160

153161
it("Single underscore section with following section at higher level", function () {
154162
expect(
155-
pattern.prototype.extractSection(
163+
Pattern.prototype.extractSection(
156164
"My title\n-------\nContent\n\nNext\n====\n",
157165
"My title"
158166
)
@@ -162,6 +170,8 @@ describe("pat-markdown", function () {
162170

163171
describe("Code blocks", function () {
164172
it("It correctly renders code blocks", async function () {
173+
await import("../syntax-highlight/syntax-highlight");
174+
165175
document.body.innerHTML = `
166176
<main>
167177
<div class="pat-markdown">
@@ -177,9 +187,8 @@ some content
177187
</main>
178188
`;
179189

180-
new pattern(document.querySelector(".pat-markdown"));
181-
await utils.timeout(1); // wait a tick for async to settle.
182-
await utils.timeout(1); // wait a tick for async to settle.
190+
const instance = new Pattern(document.querySelector(".pat-markdown"));
191+
await events.await_pattern_init(instance);
183192

184193
expect(document.body.querySelector("main > div > h1").textContent).toBe("Title"); // prettier-ignore
185194
expect(document.body.querySelector("main > div > p").textContent).toBe("some content"); // prettier-ignore

0 commit comments

Comments
 (0)