Skip to content

Commit 799e33c

Browse files
author
Smart Cloud Solutions Inc.
committed
fix(gatey): harden frontend mounting and unify race-condition protection in shared helper
1 parent 2a7ed73 commit 799e33c

16 files changed

Lines changed: 171 additions & 103 deletions

File tree

gatey-blocks/dist/account-attribute/block.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"$schema": "https://schemas.wp.org/trunk/block.json",
33
"apiVersion": 3,
44
"name": "gatey/account-attribute",
5-
"version": "2.2.1",
5+
"version": "2.2.2",
66
"title": "Account Attribute",
77
"category": "smartcloud-gatey",
88
"description": "Account Attribute for Gatey Authenticator - display an attribute of the current user",

gatey-blocks/dist/authenticator/block.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"$schema": "https://schemas.wp.org/trunk/block.json",
33
"apiVersion": 3,
44
"name": "gatey/authenticator",
5-
"version": "2.2.2",
5+
"version": "2.2.3",
66
"title": "Authenticator",
77
"category": "smartcloud-gatey",
88
"description": "Gatey Authenticator - add authentication screens to your site",

gatey-blocks/dist/view.asset.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<?php return array('dependencies' => array('jquery', 'react', 'react-dom', 'react-jsx-runtime', 'wp-data', 'wp-element'), 'version' => '1ea708522074026e40bb');
1+
<?php return array('dependencies' => array('jquery', 'react', 'react-dom', 'react-jsx-runtime', 'wp-data', 'wp-element'), 'version' => '39a2c993c43dc7bbe64c');

gatey-blocks/dist/view.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gatey-blocks/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@smart-cloud/gatey-blocks",
33
"private": true,
4-
"version": "2.2.2",
4+
"version": "2.2.3",
55
"type": "module",
66
"license": "ISC",
77
"scripts": {

gatey-blocks/src/account-attribute/block.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"$schema": "https://schemas.wp.org/trunk/block.json",
33
"apiVersion": 3,
44
"name": "gatey/account-attribute",
5-
"version": "2.2.1",
5+
"version": "2.2.2",
66
"title": "Account Attribute",
77
"category": "smartcloud-gatey",
88
"description": "Account Attribute for Gatey Authenticator - display an attribute of the current user",

gatey-blocks/src/account-attribute/view.tsx

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import "jquery";
55

66
import { getStore } from "@smart-cloud/gatey-core";
77

8+
import { beginMount, endMount, resetMount } from "../shared/mountGuard";
89
import { Theme } from "./theme";
910

1011
const cache = new Map<string, string>();
@@ -13,51 +14,55 @@ try {
1314
const call = async (id: string) => {
1415
const el = document.querySelector("#" + id);
1516
if (el) {
16-
jQuery(el).data("rendered", "true");
17+
if (!beginMount(id, el)) {
18+
return;
19+
}
1720

18-
// Simple decode of single data-config attribute
19-
const configAttr = el.getAttribute("data-config");
20-
const config = configAttr ? JSON.parse(atob(configAttr)) : {};
21+
try {
22+
// Simple decode of single data-config attribute
23+
const configAttr = el.getAttribute("data-config");
24+
const config = configAttr ? JSON.parse(atob(configAttr)) : {};
2125

22-
const isPreview = el.getAttribute("data-is-preview") === "true";
26+
const isPreview = el.getAttribute("data-is-preview") === "true";
2327

24-
// Parse link if it's a JSON string
25-
if (config.link && typeof config.link === "string") {
26-
try {
27-
config.link = JSON.parse(config.link);
28-
} catch {
29-
/** */
28+
// Parse link if it's a JSON string
29+
if (config.link && typeof config.link === "string") {
30+
try {
31+
config.link = JSON.parse(config.link);
32+
} catch {
33+
/** */
34+
}
3035
}
31-
}
3236

33-
const root = createRoot(el);
34-
const fulfilledStore = await getStore();
35-
if (cache.has(id)) {
36-
el.innerHTML = cache.get(id) || "";
37-
} else {
38-
cache.set(id, el.innerHTML || "");
37+
const root = createRoot(el);
38+
const fulfilledStore = await getStore();
39+
if (cache.has(id)) {
40+
el.innerHTML = cache.get(id) || "";
41+
} else {
42+
cache.set(id, el.innerHTML || "");
43+
}
44+
root.render(
45+
<StrictMode>
46+
<Theme
47+
id={id}
48+
isPreview={isPreview}
49+
store={fulfilledStore}
50+
{...config}
51+
/>
52+
</StrictMode>,
53+
);
54+
} catch (error) {
55+
resetMount(el);
56+
throw error;
57+
} finally {
58+
endMount(id);
3959
}
40-
root.render(
41-
<StrictMode>
42-
<Theme
43-
id={id}
44-
isPreview={isPreview}
45-
store={fulfilledStore}
46-
{...config}
47-
/>
48-
</StrictMode>,
49-
);
5060
}
5161
};
5262

5363
jQuery(document).on("smartcloud-gatey-account-attribute-block", (_, id) =>
5464
call(id),
5565
);
56-
jQuery(window).on("elementor/frontend/init", function () {
57-
jQuery(document).on("smartcloud-gatey-account-attribute-block", (_, id) =>
58-
call(id),
59-
);
60-
});
6166
} catch (err) {
6267
console.error(err);
6368
}

gatey-blocks/src/authenticator/block.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"$schema": "https://schemas.wp.org/trunk/block.json",
33
"apiVersion": 3,
44
"name": "gatey/authenticator",
5-
"version": "2.2.2",
5+
"version": "2.2.3",
66
"title": "Authenticator",
77
"category": "smartcloud-gatey",
88
"description": "Gatey Authenticator - add authentication screens to your site",

gatey-blocks/src/authenticator/view.tsx

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import "jquery";
55

66
import { getStore } from "@smart-cloud/gatey-core";
77

8+
import { beginMount, endMount, resetMount } from "../shared/mountGuard";
89
import { ThemedApp } from "./theme";
910

1011
const cache = new Map<string, string>();
@@ -13,44 +14,48 @@ try {
1314
const call = async (id: string) => {
1415
const el = document.querySelector("#" + id);
1516
if (el) {
16-
jQuery(el).data("rendered", "true");
17-
18-
// Simple decode of single data-config attribute
19-
const configAttr = el.getAttribute("data-config");
20-
const config = configAttr ? JSON.parse(atob(configAttr)) : {};
21-
22-
const isPreview = el.getAttribute("data-is-preview") === "true";
17+
if (!beginMount(id, el)) {
18+
return;
19+
}
2320

24-
const root = createRoot(el);
25-
const fulfilledStore = await getStore();
26-
if (cache.has(id)) {
27-
el.innerHTML = cache.get(id) || "";
28-
} else {
29-
cache.set(id, el.innerHTML || "");
21+
try {
22+
// Simple decode of single data-config attribute
23+
const configAttr = el.getAttribute("data-config");
24+
const config = configAttr ? JSON.parse(atob(configAttr)) : {};
25+
26+
const isPreview = el.getAttribute("data-is-preview") === "true";
27+
28+
const root = createRoot(el);
29+
const fulfilledStore = await getStore();
30+
if (cache.has(id)) {
31+
el.innerHTML = cache.get(id) || "";
32+
} else {
33+
cache.set(id, el.innerHTML || "");
34+
}
35+
root.render(
36+
<StrictMode>
37+
<ThemedApp
38+
id={id}
39+
store={fulfilledStore}
40+
isPreview={isPreview}
41+
{...config}
42+
>
43+
{el.children?.length && el.children[0].innerHTML}
44+
</ThemedApp>
45+
</StrictMode>,
46+
);
47+
} catch (error) {
48+
resetMount(el);
49+
throw error;
50+
} finally {
51+
endMount(id);
3052
}
31-
root.render(
32-
<StrictMode>
33-
<ThemedApp
34-
id={id}
35-
store={fulfilledStore}
36-
isPreview={isPreview}
37-
{...config}
38-
>
39-
{el.children?.length && el.children[0].innerHTML}
40-
</ThemedApp>
41-
</StrictMode>,
42-
);
4353
}
4454
};
4555

4656
jQuery(document).on("smartcloud-gatey-authenticator-block", (_, id) =>
4757
call(id),
4858
);
49-
jQuery(window).on("elementor/frontend/init", function () {
50-
jQuery(document).on("smartcloud-gatey-authenticator-block", (_, id) =>
51-
call(id),
52-
);
53-
});
5459
} catch (err) {
5560
console.error(err);
5661
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import "jquery";
2+
3+
const mounting = new Set<string>();
4+
5+
export function beginMount(id: string, el: Element): boolean {
6+
if (!id || mounting.has(id) || jQuery(el).data("rendered")) {
7+
return false;
8+
}
9+
10+
mounting.add(id);
11+
jQuery(el).data("rendered", "true");
12+
return true;
13+
}
14+
15+
export function endMount(id: string): void {
16+
mounting.delete(id);
17+
}
18+
19+
export function resetMount(el: Element): void {
20+
jQuery(el).removeData("rendered");
21+
}

0 commit comments

Comments
 (0)