@roomle/embedding-lib 4.37.0 → 4.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/__sidebar__.json +14 -0
- package/docs/api/classes/exposed_analytics_callbacks.ExposedAnalyticsCallbacks.md +1 -1
- package/docs/api/classes/exposed_api.ExposedApi.md +11 -11
- package/docs/api/classes/exposed_callbacks.ExposedCallbacks.md +31 -7
- package/docs/api/classes/roomle_configurator_api.default.md +9 -9
- package/docs/api/enums/types.UI_BUTTON.md +33 -22
- package/docs/api/interfaces/exposed_callbacks.Labels.md +2 -2
- package/docs/api/interfaces/exposed_callbacks.Price.md +2 -2
- package/docs/api/interfaces/roomle_configurator_api.RoomleEmbeddingApiKeys.md +4 -4
- package/docs/api/interfaces/types.ConfiguratorSettings.md +5 -5
- package/docs/api/interfaces/types.EmbeddingSkin.md +5 -5
- package/docs/api/interfaces/types.UiInitData.md +31 -16
- package/docs/api/modules/roomle_configurator_api.md +3 -3
- package/docs/examples/11_light_settings.html +90 -62
- package/docs/examples/roomle-configurator-api.es.min.js +254 -58
- package/docs/hsp.md +61 -0
- package/docs/integration.md +1101 -0
- package/docs/md/web/ui/EMBEDDING-CHANGELOG.md +14 -2
- package/docs/migration-guides/v2-to-v3.md +2 -2
- package/docs/moc/index.md +86 -0
- package/docs/simple.md +1 -1
- package/package.json +2 -2
- package/types/index.d.ts +53 -28
- package/types/src/common/business-logic/connector.d.ts +8 -0
- package/types/src/common/store/collection-view-state.d.ts +8 -3
- package/types/src/common/store/common-ui-state.d.ts +1 -1
- package/types/src/common/store/index.d.ts +0 -1
- package/types/src/common/utils/touch-drag.d.ts +6 -1
- package/types/src/configurator/business-logic/roomle-sdk-wrapper.d.ts +2 -0
- package/types/src/configurator/business-logic/sdk-connector-configurator.d.ts +3 -5
- package/types/src/configurator/business-logic/sdk-connector.d.ts +4 -7
- package/types/src/configurator/embedding/exposed-api.d.ts +1 -1
- package/types/src/configurator/embedding/exposed-callbacks.d.ts +7 -1
- package/types/src/configurator/embedding/types.d.ts +8 -1
- package/types/src/configurator/store/ui-state.d.ts +1 -0
- package/types/src/planner/business-logic/sdk-connector-planner.d.ts +3 -3
- package/types/src/planner/store/planner-ui-state.d.ts +3 -2
- package/types/src/planner/utils/planner-sidebar.d.ts +0 -1
- package/types/src/viewer/business-logic/sdk-connector-viewer.d.ts +2 -2
- package/types/tests/helpers/data/part-list.d.ts +16 -0
- package/types/tests/helpers/mocks/sdk-connector.d.ts +1 -0
- package/types/tests/integration/{configurator → common}/components/BottomBar.spec.d.ts +0 -0
- package/types/tests/integration/planner/components/{BottomBar.spec.d.ts → PlannerSidebar.spec.d.ts} +0 -0
- package/docs/index.md +0 -846
|
@@ -50,10 +50,10 @@ class MessageHandler {
|
|
|
50
50
|
};
|
|
51
51
|
let command = '';
|
|
52
52
|
try {
|
|
53
|
-
command = JSON.stringify({message, args});
|
|
53
|
+
command = JSON.stringify({ message, args });
|
|
54
54
|
}
|
|
55
55
|
catch (e) {
|
|
56
|
-
return reject(new Error(this._side + ': can not create command
|
|
56
|
+
return reject(new Error(this._side + ': can not create command because it is not JSON.stringify able'));
|
|
57
57
|
}
|
|
58
58
|
if (!this._outgoingMessageBus) {
|
|
59
59
|
return reject(new Error(this._side + ': outgoing bus not set yet'));
|
|
@@ -68,7 +68,7 @@ class MessageHandler {
|
|
|
68
68
|
try {
|
|
69
69
|
const command = JSON.parse(event.data);
|
|
70
70
|
if (!this._execMessage) {
|
|
71
|
-
return receiver.postMessage(JSON.stringify({error: this._side + ' is not ready to handle messages'}));
|
|
71
|
+
return receiver.postMessage(JSON.stringify({ error: this._side + ' is not ready to handle messages' }));
|
|
72
72
|
}
|
|
73
73
|
if (!Array.isArray(command.args)) {
|
|
74
74
|
command.args = [command.args];
|
|
@@ -87,19 +87,20 @@ class MessageHandler {
|
|
|
87
87
|
result = data.result;
|
|
88
88
|
}
|
|
89
89
|
if (error) {
|
|
90
|
-
receiver.postMessage(JSON.stringify({error}));
|
|
91
|
-
}
|
|
92
|
-
|
|
90
|
+
receiver.postMessage(JSON.stringify({ error }));
|
|
91
|
+
}
|
|
92
|
+
else if (result !== undefined) {
|
|
93
|
+
receiver.postMessage(JSON.stringify({ result }));
|
|
93
94
|
}
|
|
94
95
|
else {
|
|
95
|
-
receiver.postMessage(JSON.stringify({result: data}));
|
|
96
|
+
receiver.postMessage(JSON.stringify({ result: data }));
|
|
96
97
|
}
|
|
97
98
|
}, (error) => {
|
|
98
|
-
receiver.postMessage(JSON.stringify({error: this._prepareError(error)}));
|
|
99
|
+
receiver.postMessage(JSON.stringify({ error: this._prepareError(error) }));
|
|
99
100
|
});
|
|
100
101
|
}
|
|
101
102
|
catch (error) {
|
|
102
|
-
receiver.postMessage(JSON.stringify({error: this._prepareError(error)}));
|
|
103
|
+
receiver.postMessage(JSON.stringify({ error: this._prepareError(error) }));
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
}
|
|
@@ -115,49 +116,25 @@ class MessageHandler {
|
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
/**
|
|
119
|
-
* Recursively merge properties of two objects.
|
|
120
|
-
* If a property exists in both it, property of obj2 is used
|
|
121
|
-
* @param obj1
|
|
122
|
-
* @param obj2
|
|
123
|
-
*/
|
|
124
|
-
const deepMerge = (obj1, obj2) => {
|
|
125
|
-
// tslint:disable-next-line
|
|
126
|
-
for (const p in obj2) {
|
|
127
|
-
try {
|
|
128
|
-
// Property in destination object set; update its value.
|
|
129
|
-
if (obj2[p].constructor === Object) {
|
|
130
|
-
obj1[p] = deepMerge(obj1[p], obj2[p]);
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
obj1[p] = obj2[p];
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
catch (e) {
|
|
137
|
-
// Property in destination object not set; create it and set its value.
|
|
138
|
-
obj1[p] = obj2[p];
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return obj1;
|
|
142
|
-
};
|
|
143
|
-
|
|
144
119
|
const NAMESPACE_SEPARATOR = '.';
|
|
145
120
|
const HANDSHAKE_MESSAGES = {
|
|
146
121
|
REQUEST_BOOT: 'requestBoot',
|
|
147
122
|
SETUP: 'setup',
|
|
148
123
|
WEBSITE_READY: 'websiteReady',
|
|
149
124
|
};
|
|
150
|
-
const getConfiguratorSettings = async (configuratorId) => {
|
|
125
|
+
const getConfiguratorSettings = async (configuratorId, initData) => {
|
|
151
126
|
if (typeof configuratorId !== 'string') {
|
|
152
127
|
throw new Error('Configurator ID is not a string type: "' + (typeof configuratorId) + '"');
|
|
153
128
|
}
|
|
154
|
-
const
|
|
129
|
+
const server = initData.customApiUrl ? initData.customApiUrl : 'https://api.roomle.com/v2';
|
|
130
|
+
const currentTenant = initData.overrideTenant || 9;
|
|
131
|
+
const url = server + '/configurators/' + configuratorId;
|
|
155
132
|
const apiKey = 'roomle_portal_v2';
|
|
156
133
|
const token = '03-' + window.btoa((new Date()).toISOString() + ';anonymous;' + apiKey);
|
|
157
134
|
const createHeaders = () => {
|
|
158
135
|
const headers = {
|
|
159
136
|
apiKey,
|
|
160
|
-
currentTenant
|
|
137
|
+
currentTenant,
|
|
161
138
|
locale: 'en',
|
|
162
139
|
language: 'en',
|
|
163
140
|
device: 1,
|
|
@@ -173,16 +150,173 @@ const getConfiguratorSettings = async (configuratorId) => {
|
|
|
173
150
|
cache: 'default',
|
|
174
151
|
});
|
|
175
152
|
const response = await fetch(request);
|
|
176
|
-
const {configurator} = await response.json();
|
|
153
|
+
const { configurator } = await response.json();
|
|
177
154
|
return configurator;
|
|
178
155
|
};
|
|
156
|
+
|
|
157
|
+
const isInIframe = () => {
|
|
158
|
+
try {
|
|
159
|
+
return window.self !== window.top;
|
|
160
|
+
}
|
|
161
|
+
catch (e) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const NAMES_FOR_LOCALHOST = [
|
|
167
|
+
'127.0.0.1',
|
|
168
|
+
'localhost',
|
|
169
|
+
'0.0.0.0',
|
|
170
|
+
];
|
|
171
|
+
const getHostname = () => {
|
|
172
|
+
const isIframe = isInIframe();
|
|
173
|
+
let url = window.location.href;
|
|
174
|
+
if (isIframe) {
|
|
175
|
+
if (!document.referrer) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
url = document.referrer;
|
|
179
|
+
}
|
|
180
|
+
const { hostname } = new URL(url);
|
|
181
|
+
return hostname;
|
|
182
|
+
};
|
|
183
|
+
const isDemoHostname = (hostname) => {
|
|
184
|
+
if (NAMES_FOR_LOCALHOST.includes(hostname)) {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
if (hostname.endsWith('roomle.com')) {
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
// exception for CI builds
|
|
191
|
+
if (hostname.endsWith('gitlab.io') || hostname.endsWith('gitlab.com')) {
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Recursively merge properties of two objects.
|
|
199
|
+
* If a property exists in both it, property of obj2 is used.
|
|
200
|
+
* Returns a new object (copy)
|
|
201
|
+
* @param obj1
|
|
202
|
+
* @param obj2
|
|
203
|
+
*/
|
|
204
|
+
const deepMergeCopy = (obj1, obj2) => {
|
|
205
|
+
const result = JSON.parse(JSON.stringify(obj1));
|
|
206
|
+
return deepMerge(result, obj2);
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* Recursively merge properties of two objects.
|
|
210
|
+
* If a property exists in both it, property of obj2 is used.
|
|
211
|
+
* Warning: This returns obj1 and not a copy!
|
|
212
|
+
* @param obj1
|
|
213
|
+
* @param obj2
|
|
214
|
+
*/
|
|
215
|
+
const deepMerge = (obj1, obj2) => {
|
|
216
|
+
// tslint:disable-next-line
|
|
217
|
+
for (const p in obj2) {
|
|
218
|
+
try {
|
|
219
|
+
// Property in destination object set; update its value.
|
|
220
|
+
if (obj2[p].constructor === Object) {
|
|
221
|
+
obj1[p] = deepMerge(obj1[p], obj2[p]);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
obj1[p] = obj2[p];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
catch (e) {
|
|
228
|
+
// Property in destination object not set; create it and set its value.
|
|
229
|
+
obj1[p] = obj2[p];
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return obj1;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const BROWSER_LANGUAGE_PROPERTY_KEYS_KNOWN = ['language', 'browserLanguage', 'userLanguage', 'systemLanguage'];
|
|
236
|
+
const getLanguage = (lang = null) => {
|
|
237
|
+
const navigator = window.navigator;
|
|
238
|
+
if (lang) {
|
|
239
|
+
return lang.substr(0, 2);
|
|
240
|
+
}
|
|
241
|
+
if (Array.isArray(navigator.languages) && navigator.languages.length > 0) {
|
|
242
|
+
return navigator.languages[0].substr(0, 2);
|
|
243
|
+
}
|
|
244
|
+
for (let i = 0, length = BROWSER_LANGUAGE_PROPERTY_KEYS_KNOWN.length; i < length; i++) {
|
|
245
|
+
const language = navigator[BROWSER_LANGUAGE_PROPERTY_KEYS_KNOWN[i]];
|
|
246
|
+
if (language) {
|
|
247
|
+
return language.substr(0, 2);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return 'en';
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const CONFIGURATOR_IDLE = '(idle)';
|
|
254
|
+
const castAndFixInitData = (initData) => {
|
|
255
|
+
castInitData(initData);
|
|
256
|
+
if (initData === null || initData === void 0 ? void 0 : initData.customApiUrl) {
|
|
257
|
+
initData.customApiUrl = decodeURIComponent(initData.customApiUrl);
|
|
258
|
+
}
|
|
259
|
+
if (initData.shareUrl) {
|
|
260
|
+
initData.deeplink = initData.shareUrl.replace(LEGACY_SHARE_PLACEHOLDER, SHARE_PLACEHOLDER);
|
|
261
|
+
}
|
|
262
|
+
return initData;
|
|
263
|
+
};
|
|
264
|
+
const castInitData = (obj) => {
|
|
265
|
+
if (!obj) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const keys = Object.keys(obj);
|
|
269
|
+
for (const key of keys) {
|
|
270
|
+
const value = obj[key];
|
|
271
|
+
// need to type-check for null because typeof null evaluates to object
|
|
272
|
+
// see here why this is like it is: https://2ality.com/2013/10/typeof-null.html
|
|
273
|
+
if (!Array.isArray(value) && typeof value === 'object' && value !== null) {
|
|
274
|
+
return castInitData(value);
|
|
275
|
+
}
|
|
276
|
+
if (Array.isArray(value)) {
|
|
277
|
+
for (const entry of value) {
|
|
278
|
+
castInitData(entry);
|
|
279
|
+
}
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (value === 'true' || value === 'false') {
|
|
283
|
+
obj[key] = value === 'true';
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
};
|
|
179
287
|
const mergeInitData = (configuratorSettings, currentInitData) => {
|
|
180
288
|
currentInitData.configuratorId = configuratorSettings.id;
|
|
181
289
|
const remoteInitData = configuratorSettings.settings || {};
|
|
182
|
-
|
|
290
|
+
// This is a performance optimization so we do not need to fetch
|
|
291
|
+
// configurator settings twice
|
|
292
|
+
if (!currentInitData.overrideTenant && configuratorSettings.tenant) {
|
|
293
|
+
// use as any because we send tenant id as string but SDK requires to send a number
|
|
294
|
+
// casting to number could become a problem when we change tenant IDs to something
|
|
295
|
+
// random instead of a integer which is incremented
|
|
296
|
+
currentInitData.overrideTenant = configuratorSettings.tenant;
|
|
297
|
+
}
|
|
298
|
+
return deepMergeCopy(remoteInitData, currentInitData);
|
|
299
|
+
};
|
|
300
|
+
const getFallbackInitData = () => {
|
|
301
|
+
const fallbackInitData = {};
|
|
302
|
+
if (!fallbackInitData.locale) {
|
|
303
|
+
fallbackInitData.locale = getLanguage();
|
|
304
|
+
}
|
|
305
|
+
if (fallbackInitData.id === CONFIGURATOR_IDLE) {
|
|
306
|
+
delete fallbackInitData.id;
|
|
307
|
+
}
|
|
308
|
+
const hostname = getHostname();
|
|
309
|
+
if (hostname && isDemoHostname(hostname)) {
|
|
310
|
+
fallbackInitData.configuratorId = 'demoConfigurator';
|
|
311
|
+
}
|
|
312
|
+
fallbackInitData.customApiUrl = 'https://www.roomle.com/api/v2';
|
|
313
|
+
fallbackInitData.emails = false;
|
|
314
|
+
return fallbackInitData;
|
|
183
315
|
};
|
|
316
|
+
const LEGACY_SHARE_PLACEHOLDER = '<CONF_ID>';
|
|
317
|
+
const SHARE_PLACEHOLDER = '#CONFIGURATIONID#';
|
|
184
318
|
|
|
185
|
-
// see why:
|
|
319
|
+
// see why: so#/58065241/10800831
|
|
186
320
|
const isAndroid = () => /(android)/i.test(navigator.userAgent);
|
|
187
321
|
|
|
188
322
|
const setDefaultBehaviour = (object, callbackName, defaultBehaviour) => {
|
|
@@ -222,7 +356,8 @@ const RML_CSS_CLASSES = {
|
|
|
222
356
|
ANDROID_HEIGHT: 'rml-android-height',
|
|
223
357
|
OVERFLOW_HIDDEN: 'rml-overflow-hidden',
|
|
224
358
|
};
|
|
225
|
-
|
|
359
|
+
const globalSetupDone = new Map();
|
|
360
|
+
class RoomleEmbeddingApi {
|
|
226
361
|
constructor(settings, container, initData, waitForIframe) {
|
|
227
362
|
this.ui = {
|
|
228
363
|
callbacks: null,
|
|
@@ -233,10 +368,16 @@ class RoomleConfiguratorApi {
|
|
|
233
368
|
this.analytics = {
|
|
234
369
|
callbacks: {},
|
|
235
370
|
};
|
|
371
|
+
this.global = {
|
|
372
|
+
callbacks: {},
|
|
373
|
+
};
|
|
236
374
|
this._initData = {};
|
|
237
375
|
if (!settings || typeof settings.id !== 'string') {
|
|
238
376
|
throw new Error('Please provide a correct configuratorId, you get the correct ID from your Roomle Contact Person');
|
|
239
377
|
}
|
|
378
|
+
if (globalSetupDone.has(container)) {
|
|
379
|
+
throw new Error('There is already an instance on this DOM element');
|
|
380
|
+
}
|
|
240
381
|
const stylesAlreadyAdded = !!document.getElementById(RML_STYLES_ID);
|
|
241
382
|
if (!stylesAlreadyAdded) {
|
|
242
383
|
const zIndex = initData.zIndex || 9999999;
|
|
@@ -247,13 +388,13 @@ class RoomleConfiguratorApi {
|
|
|
247
388
|
const cssTransitionForAllBrowsers = ['-webkit-', '-o-'].reduce((acc, browser) => acc += browser + cssTransition, '') + cssTransition;
|
|
248
389
|
const vh = calcVh();
|
|
249
390
|
styles.innerHTML = `
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
391
|
+
.${RML_CSS_CLASSES.CONTAINER}{${RML_CUSTOM_PROPERTY_HEIGHT}:${vh};}
|
|
392
|
+
.${RML_CSS_CLASSES.POSITION}{position:fixed;top:0;left:0;z-index:${zIndex};opacity:0}
|
|
393
|
+
.${RML_CSS_CLASSES.TRANSITION}{${cssTransitionForAllBrowsers}}
|
|
394
|
+
.${RML_CSS_CLASSES.FILL}{width:100%;height:100%;opacity:1}
|
|
395
|
+
.${RML_CSS_CLASSES.ANDROID_HEIGHT}{height:calc(var(${RML_CUSTOM_PROPERTY_HEIGHT},1vh)*100)}
|
|
396
|
+
.${RML_CSS_CLASSES.OVERFLOW_HIDDEN}{overflow:hidden}
|
|
397
|
+
`;
|
|
257
398
|
document.head.appendChild(styles);
|
|
258
399
|
}
|
|
259
400
|
this._onResize = this._onResize.bind(this);
|
|
@@ -271,6 +412,10 @@ class RoomleConfiguratorApi {
|
|
|
271
412
|
this._waitForIframe = waitForIframe;
|
|
272
413
|
this._container.appendChild(iframe);
|
|
273
414
|
this._iframe = iframe;
|
|
415
|
+
globalSetupDone.set(container, true);
|
|
416
|
+
}
|
|
417
|
+
static createPlanner(configuratorId, container, initData) {
|
|
418
|
+
return this._create(configuratorId, container, initData);
|
|
274
419
|
}
|
|
275
420
|
/**
|
|
276
421
|
* Method to create a new instance of a Roomle Configurator
|
|
@@ -278,11 +423,43 @@ class RoomleConfiguratorApi {
|
|
|
278
423
|
* @param container DOM container in which the configurator should be placed
|
|
279
424
|
* @param initData settings with which the configurator should be started
|
|
280
425
|
*/
|
|
426
|
+
static createConfigurator(configuratorId, container, initData) {
|
|
427
|
+
return this._create(configuratorId, container, initData);
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Method to create a new instance of a Roomle Configurator
|
|
431
|
+
* @deprecated please use "createConfigurator"
|
|
432
|
+
* @param configuratorId the id which identifies your configurator, you will get this ID from your Roomle Contact Person
|
|
433
|
+
* @param container DOM container in which the configurator should be placed
|
|
434
|
+
* @param initData settings with which the configurator should be started
|
|
435
|
+
*/
|
|
281
436
|
static create(configuratorId, container, initData) {
|
|
437
|
+
return this._create(configuratorId, container, initData);
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Method to create a new instance of a Roomle Viewer
|
|
441
|
+
* @param configuratorId the id which identifies your configurator, you will get this ID from your Roomle Contact Person
|
|
442
|
+
* @param container DOM container in which the configurator should be placed
|
|
443
|
+
* @param initData settings with which the configurator should be started
|
|
444
|
+
*/
|
|
445
|
+
static createViewer(configuratorId, container, initData) {
|
|
446
|
+
return this._create(configuratorId, container, initData);
|
|
447
|
+
}
|
|
448
|
+
static _create(configuratorId, container, initData) {
|
|
282
449
|
return new Promise(async (resolve, reject) => {
|
|
283
450
|
try {
|
|
284
|
-
const
|
|
285
|
-
|
|
451
|
+
const fallbackInitData = deepMerge(getFallbackInitData(), castAndFixInitData(initData));
|
|
452
|
+
if (!fallbackInitData.featureFlags) {
|
|
453
|
+
fallbackInitData.featureFlags = {};
|
|
454
|
+
}
|
|
455
|
+
if (typeof fallbackInitData.featureFlags.realPartList !== 'boolean') {
|
|
456
|
+
fallbackInitData.featureFlags.realPartList = true;
|
|
457
|
+
}
|
|
458
|
+
if (typeof fallbackInitData.featureFlags.globalCallbacks !== 'boolean') {
|
|
459
|
+
fallbackInitData.featureFlags.globalCallbacks = true;
|
|
460
|
+
}
|
|
461
|
+
const configuratorSettings = await getConfiguratorSettings(configuratorId, fallbackInitData);
|
|
462
|
+
initData = mergeInitData(configuratorSettings, fallbackInitData);
|
|
286
463
|
return new this(configuratorSettings, container, initData, resolve);
|
|
287
464
|
}
|
|
288
465
|
catch (e) {
|
|
@@ -291,6 +468,13 @@ class RoomleConfiguratorApi {
|
|
|
291
468
|
});
|
|
292
469
|
}
|
|
293
470
|
teardown() {
|
|
471
|
+
if (this._container) {
|
|
472
|
+
globalSetupDone.delete(this._container);
|
|
473
|
+
}
|
|
474
|
+
const iframe = this._container.querySelector('iframe');
|
|
475
|
+
if (iframe) {
|
|
476
|
+
this._container.removeChild(iframe);
|
|
477
|
+
}
|
|
294
478
|
window.removeEventListener('resize', this._onResize);
|
|
295
479
|
}
|
|
296
480
|
_createIframe() {
|
|
@@ -329,7 +513,7 @@ class RoomleConfiguratorApi {
|
|
|
329
513
|
document.documentElement.classList.remove(RML_CSS_CLASSES.OVERFLOW_HIDDEN);
|
|
330
514
|
window.document.body.classList.remove(RML_CSS_CLASSES.OVERFLOW_HIDDEN);
|
|
331
515
|
}
|
|
332
|
-
_executeMessage({message, args}, event) {
|
|
516
|
+
_executeMessage({ message, args }, event) {
|
|
333
517
|
var _a;
|
|
334
518
|
if (!event.source) {
|
|
335
519
|
// @ts-ignore
|
|
@@ -341,14 +525,17 @@ class RoomleConfiguratorApi {
|
|
|
341
525
|
}
|
|
342
526
|
if (message === HANDSHAKE_MESSAGES.REQUEST_BOOT) {
|
|
343
527
|
this._messageHandler.setOutgoingMessageBus(event.source);
|
|
344
|
-
return Promise.resolve({result: this._initData});
|
|
528
|
+
return Promise.resolve({ result: this._initData });
|
|
345
529
|
}
|
|
346
530
|
if (message === HANDSHAKE_MESSAGES.SETUP) {
|
|
347
|
-
const {methods, callbacks} = args[0];
|
|
531
|
+
const { methods, callbacks } = args[0];
|
|
348
532
|
methods.forEach((method) => {
|
|
349
533
|
const namespaces = method.split(NAMESPACE_SEPARATOR);
|
|
350
534
|
const object = namespaces[0];
|
|
351
535
|
const methodName = namespaces[1];
|
|
536
|
+
if (!this[object]) {
|
|
537
|
+
this[object] = {};
|
|
538
|
+
}
|
|
352
539
|
this[object][methodName] = function () {
|
|
353
540
|
// @todo -- this was the fix that values are passed to caller, e.g.: interface.extended.getParametersOfRootComponent
|
|
354
541
|
// most of the things we need for a meaningful test are not available in JEST (since it runs in node). We should
|
|
@@ -361,6 +548,9 @@ class RoomleConfiguratorApi {
|
|
|
361
548
|
const object = namespaces[0];
|
|
362
549
|
const callbacksName = namespaces[1];
|
|
363
550
|
const eventName = namespaces[2];
|
|
551
|
+
if (!this[object]) {
|
|
552
|
+
this[object] = {};
|
|
553
|
+
}
|
|
364
554
|
if (!this[object][callbacksName]) {
|
|
365
555
|
this[object][callbacksName] = {};
|
|
366
556
|
}
|
|
@@ -371,7 +561,7 @@ class RoomleConfiguratorApi {
|
|
|
371
561
|
setDefaultBehaviour(this.ui.callbacks, 'onBackToWebsite', this._onBackToWebsite);
|
|
372
562
|
this._waitForIframe(this);
|
|
373
563
|
setTimeout(() => this._messageHandler.sendMessage(HANDSHAKE_MESSAGES.WEBSITE_READY), 0); // Run it after the promise is resolved so everyone can subscribe
|
|
374
|
-
return Promise.resolve({result: null});
|
|
564
|
+
return Promise.resolve({ result: null });
|
|
375
565
|
}
|
|
376
566
|
const messageNamespaces = message.split(NAMESPACE_SEPARATOR);
|
|
377
567
|
const namespace = messageNamespaces[0];
|
|
@@ -379,12 +569,18 @@ class RoomleConfiguratorApi {
|
|
|
379
569
|
const methodOfAction = (messageNamespaces.length === 3) ? messageNamespaces[2] : null;
|
|
380
570
|
if (methodOfAction) {
|
|
381
571
|
if (this[namespace][objectOfAction][methodOfAction]) {
|
|
382
|
-
this[namespace][objectOfAction][methodOfAction](...args);
|
|
383
|
-
|
|
572
|
+
const result = this[namespace][objectOfAction][methodOfAction](...args);
|
|
573
|
+
if (result instanceof Promise) {
|
|
574
|
+
return result.then((data) => ({ result: data }));
|
|
575
|
+
}
|
|
576
|
+
else if (result !== undefined) {
|
|
577
|
+
return Promise.resolve({ result });
|
|
578
|
+
}
|
|
579
|
+
return Promise.resolve({ result: null });
|
|
384
580
|
}
|
|
385
581
|
}
|
|
386
582
|
return Promise.reject('Message "' + message + '" is unkown');
|
|
387
583
|
}
|
|
388
584
|
}
|
|
389
585
|
|
|
390
|
-
export default
|
|
586
|
+
export { RoomleEmbeddingApi as default };
|
package/docs/hsp.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Api for embedding the Roomle Planner
|
|
2
|
+
|
|
3
|
+
This README outlines the details of including the Roomle Planner to your website.
|
|
4
|
+
|
|
5
|
+
## How to add the embedding API to your project
|
|
6
|
+
|
|
7
|
+
You only need to add the code which sits in `dist/roomle-embedding-api.js` to your project. We recommend doing this
|
|
8
|
+
by a package manager like [npm](https://www.npmjs.com/), [yarn](https://yarnpkg.com/lang/en/) or similar tools and a build pipe.
|
|
9
|
+
Common tools to setup a build pipe for example are [gulp](https://gulpjs.com/), [webpack](https://webpack.js.org/),
|
|
10
|
+
[grunt](https://gruntjs.com/) and many more. Every release gets a git tag so that you can specify an exact version in your
|
|
11
|
+
package manager. Locking to a certain version helps you to deliver a stable product with the features you need.
|
|
12
|
+
|
|
13
|
+
## API description
|
|
14
|
+
|
|
15
|
+
There is an auto generated API description which is available here: [doc/api.md](doc/api.md) But no one likes to read
|
|
16
|
+
documentation so maybe it's enough to checkout the "help your self section".
|
|
17
|
+
|
|
18
|
+
### Give me some code to copy&paste
|
|
19
|
+
|
|
20
|
+
This is only a snipped to get you started! Please adjust to your needs and don't use it in production! Also this code will
|
|
21
|
+
only work in the newest browser. So use the ES version you need for your users. e.g. replace `async/await` with `Promise.then`.
|
|
22
|
+
Never use the direct link to the Roomle JS library since it is always the latest one you have no chance to rely on a certain
|
|
23
|
+
version.
|
|
24
|
+
|
|
25
|
+
```html
|
|
26
|
+
<!DOCTYPE html>
|
|
27
|
+
<html>
|
|
28
|
+
<head>
|
|
29
|
+
<meta charset="utf-8">
|
|
30
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
31
|
+
<title>Roomle Planner</title>
|
|
32
|
+
<meta name="description" content="">
|
|
33
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
34
|
+
<style>
|
|
35
|
+
body {
|
|
36
|
+
margin: 0;
|
|
37
|
+
padding: 0;
|
|
38
|
+
overflow: hidden;
|
|
39
|
+
}
|
|
40
|
+
#planner-container {
|
|
41
|
+
width:100%;
|
|
42
|
+
height:100vh;
|
|
43
|
+
}
|
|
44
|
+
</style>
|
|
45
|
+
</head>
|
|
46
|
+
|
|
47
|
+
<body>
|
|
48
|
+
<div id="planner-container"></div>
|
|
49
|
+
<script src="https://www.roomle.com/t/embedding/roomle-embedding-api.js"></script>
|
|
50
|
+
<script>
|
|
51
|
+
document.addEventListener('DOMContentLoaded', async function () {
|
|
52
|
+
try {
|
|
53
|
+
await RoomleEmbedding.initPlanner('8a701c314b4ae57f014b539159a01517');
|
|
54
|
+
} catch(error) {
|
|
55
|
+
console.error(error);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
</script>
|
|
59
|
+
</body>
|
|
60
|
+
</html>
|
|
61
|
+
```
|