diff --git a/src/framework/handlers/template.js b/src/framework/handlers/template.js index c580999d45e..c4f915f95da 100644 --- a/src/framework/handlers/template.js +++ b/src/framework/handlers/template.js @@ -52,6 +52,18 @@ class TemplateHandler extends ResourceHandler { this.decoder ??= new TextDecoder('utf-8'); return new Template(this._app, JSON.parse(this.decoder.decode(data))); } + + patch(asset, registry) { + // only process if this looks like valid template data + if (!asset || !asset.resource || !asset.data || !asset.data.entities) { + return; + } + + const template = asset.resource; + + // the `data` setter will handle cache invalidation + template.data = asset.data; + } } export { TemplateHandler }; diff --git a/src/framework/template.js b/src/framework/template.js index 4af2ef95d4a..b3493ce157a 100644 --- a/src/framework/template.js +++ b/src/framework/template.js @@ -54,6 +54,16 @@ class Template { this._templateRoot = parser.parse(this._data); } + + set data(value) { + this._data = value; + // cache invalidation: the next instantiate() will parse and use the new _data + this._templateRoot = null; + } + + get data() { + return this._data; + } } export { Template }; diff --git a/test/framework/handlers/template-handler.test.mjs b/test/framework/handlers/template-handler.test.mjs new file mode 100644 index 00000000000..2919e4588c4 --- /dev/null +++ b/test/framework/handlers/template-handler.test.mjs @@ -0,0 +1,67 @@ +import { expect } from 'chai'; + +import { Asset } from '../../../src/framework/asset/asset.js'; +import { createApp } from '../../app.mjs'; +import { jsdomSetup, jsdomTeardown } from '../../jsdom.mjs'; + +// Example template data in the database +function createFakeTemplateData(name) { + const rootId = 'root-guid'; + return { + entities: { + [rootId]: { + name, + resource_id: rootId, + parent: null, + children: [], + position: [0, 0, 0], + rotation: [0, 0, 0], + scale: [1, 1, 1], + components: {} + } + } + }; +} + +describe('TemplateHandler', function () { + let app; + + beforeEach(function () { + jsdomSetup(); + app = createApp(); + }); + + afterEach(function () { + app?.destroy(); + app = null; + jsdomTeardown(); + }); + + + it('should reparse the new template data', function (done) { + // For this test case we pretend the data is already loaded + const file = null; + + const data1 = createFakeTemplateData('root1'); + const data2 = createFakeTemplateData('root2'); + + const templateAsset = new Asset('Template B', 'template', file, data1); + + app.assets.add(templateAsset); + app.assets.load(templateAsset); + + templateAsset.ready(function (asset) { + const first = asset.resource.instantiate(); + expect(first.name).to.equal('root1'); + + // change asset data: should trigger handler.patch and resource invalidation + asset.data = data2; + + expect(asset.resource.data).to.equal(asset.data); + + const second = asset.resource.instantiate(); + expect(second.name).to.equal('root2'); + done(); + }); + }); +});