Skip to content

Commit 204e76b

Browse files
committed
PB-390: Nested Page Builder content can fail to save when action is performed quickly
- Add additional check for the count of content types before saving
1 parent 75112d7 commit 204e76b

File tree

2 files changed

+80
-3
lines changed
  • app/code/Magento/PageBuilder/view/adminhtml/web

2 files changed

+80
-3
lines changed

app/code/Magento/PageBuilder/view/adminhtml/web/js/master-format/render/frame.js

Lines changed: 41 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/code/Magento/PageBuilder/view/adminhtml/web/ts/js/master-format/render/frame.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import $ from "jquery";
77
import ko from "knockout";
88
import engine from "Magento_Ui/js/lib/knockout/template/engine";
9+
import _ from "underscore";
910
import Config from "../../config";
1011
import ConfigInterface from "../../config.types";
1112
import ContentTypeCollectionInterface from "../../content-type-collection.types";
@@ -93,6 +94,32 @@ export function loadTemplate(name: string): Promise<string> {
9394
});
9495
}
9596

97+
/**
98+
* Assert if the render has finished
99+
*/
100+
const assertRenderFinished = _.debounce((element: HTMLElement, expectedCount: number, callback: () => {}) => {
101+
if (element.querySelectorAll("[data-content-type]").length === expectedCount) {
102+
callback();
103+
}
104+
}, 50);
105+
106+
/**
107+
* Iterate over the root container and count all content types
108+
*
109+
* @param rootContainer
110+
* @param count
111+
*/
112+
function countContentTypes(rootContainer: ContentTypeCollectionInterface, count?: number) {
113+
count = count || 0;
114+
rootContainer.getChildren()().forEach((child: ContentTypeCollectionInterface) => {
115+
++count;
116+
if (typeof child.getChildren !== "undefined" && child.getChildren()().length > 0) {
117+
count = countContentTypes(child, count);
118+
}
119+
});
120+
return count;
121+
}
122+
96123
/**
97124
* Perform a render of the provided data
98125
*
@@ -102,12 +129,23 @@ function render(message: {stageId: string, tree: TreeItem}) {
102129
return new Promise((resolve, reject) => {
103130
createRenderTree(message.stageId, message.tree).then((rootContainer: ContentTypeCollectionInterface) => {
104131
const element = document.createElement("div");
105-
engine.waitForFinishRender().then(() => {
132+
/**
133+
* Setup an event on the element to observe changes and count the expected amount of content types are
134+
* present within the content.
135+
*/
136+
const renderFinished = $.Deferred();
137+
element.addEventListener("DOMSubtreeModified", () => {
138+
assertRenderFinished(element, countContentTypes(rootContainer), renderFinished.resolve);
139+
});
140+
141+
// Combine this event with our engine waitForRenderFinish to ensure rendering is completed
142+
$.when(engine.waitForFinishRender(), renderFinished).then(() => {
106143
ko.cleanNode(element);
107144
const filtered: JQuery = filterHtml($(element));
108145
const output = decodeAllDataUrlsInString(filtered.html());
109146
resolve(output);
110147
});
148+
111149
ko.applyBindingsToNode(
112150
element,
113151
{

0 commit comments

Comments
 (0)