-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d867e5c
commit 616b6cb
Showing
3 changed files
with
301 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
name: Update docs | ||
on: | ||
workflow_dispatch: | ||
|
||
jobs: | ||
update-docs: | ||
runs-on: ubuntu-20.04 | ||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 1 | ||
path: 'showroom-iframe' | ||
- uses: actions/setup-node@v2 | ||
with: | ||
node-version: '20.x' | ||
- name: Clone docs | ||
run: | | ||
cd $GITHUB_WORKSPACE/ | ||
git config --global user.name 'GitHub Actions' | ||
git config --global user.email '[email protected]' | ||
git clone https://x-access-token:${{ secrets.TOKEN }}@github.com/elfsquad/docs.git | ||
- name: Update docs | ||
run: | | ||
npm i -g @elfsquad/tsdoc-parser | ||
tsdoc-parser $GITHUB_WORKSPACE/showroom-iframe/src/index.ts showroomIframe.json ElfsquadShowroom | ||
file="$GITHUB_WORKSPACE/docs/docs/configurator/libraries/methods/showroomIframe.ts" | ||
echo "export default $(cat showroomIframe.json)" > temp && mv temp $file | ||
cd $GITHUB_WORKSPACE/docs | ||
git checkout -b update-showroom-iframe-docs | ||
git add . | ||
git commit -m "Update documentation for @elfsquad/showroom-iframe" | ||
git push --set-upstream origin update-showroom-iframe-docs -f | ||
gh pr create --title "Update @elfsquad/showroom-iframe documentation" \ | ||
--body "This PR updates the documentation for the @elfsquad/showroom-iframe package based on the latest changes." | ||
env: | ||
GH_TOKEN: ${{ secrets.TOKEN }} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
export interface ElfsquadShowroomOptions { | ||
/** | ||
* The container to render the iframe element in. Accepts a HTMLElement or a query selector. | ||
**/ | ||
container: HTMLElement | string; | ||
|
||
/** | ||
* The URL of the Elfsquad showroom, either to the showroom itself or to a specific product. | ||
**/ | ||
url: string; | ||
} | ||
|
||
|
||
export type ScreenshotCallback = (data: { image: string }) => void; | ||
export type RequestQuoteCallback = (data: { configurationId: string }) => void; | ||
|
||
|
||
export enum ViewerEvent { | ||
ScreenshotTaken = 'elfsquad.visualization.screenshotTaken', | ||
RequestQuote = 'custom:REQUEST_QUOTE', | ||
} | ||
|
||
|
||
export class ElfsquadShowroom { | ||
private readonly nativeElement: HTMLIFrameElement; | ||
private container: HTMLElement; | ||
|
||
private readonly callbacks: { [key: string]: ((data: any) => void)[] } = {}; | ||
|
||
constructor(options: ElfsquadShowroomOptions) { | ||
this.container = this.getContainer(options); | ||
this.nativeElement = this.render(options); | ||
|
||
this.registerEventListeners(); | ||
} | ||
|
||
/** | ||
* Get the native iframe element. | ||
* @returns {HTMLIFrameElement} the native iframe element. | ||
* */ | ||
public getNativeElement(): HTMLIFrameElement { | ||
return this.nativeElement; | ||
} | ||
|
||
/** | ||
* Resets the viewer to the home camera position. | ||
* @returns {void} | ||
* */ | ||
public home(): void { | ||
this.sendMessage({ name: 'elfsquad.visualization.home' }); | ||
} | ||
|
||
/** | ||
* Toggles the visibility of the footprint. | ||
* @returns {void} | ||
* */ | ||
public toggleFootprint(): void { | ||
this.sendMessage({ name: 'elfsquad.visualization.toggleFootprint' }); | ||
} | ||
|
||
/** | ||
* Trigger a screenshot of the current view. The screenshot will be returned in the onScreenshot callback. | ||
* @returns {void} | ||
* */ | ||
public screenshot(): void { | ||
this.sendMessage({ name: 'elfsquad.visualization.screenshot' }); | ||
} | ||
|
||
/** | ||
* Register a callback function to be called when a screenshot is taken. | ||
* @param {(data: { image: string })} callback - The callback function to be called when a screenshot is taken. | ||
* @returns {void} | ||
* */ | ||
public onScreenshot(callback: ScreenshotCallback): void { | ||
this.addCallback(ViewerEvent.ScreenshotTaken, callback); | ||
} | ||
|
||
/** | ||
* Register a callback function to be called when a quote is requested. | ||
* @param {(data: { configurationId: string })} callback - The callback function to be called when a quote is requested. | ||
* @returns {void} | ||
* */ | ||
public onRequestQuote(callback: RequestQuoteCallback): void { | ||
this.addCallback(ViewerEvent.RequestQuote, callback); | ||
} | ||
|
||
private addCallback(key: ViewerEvent, callback: (data: any) => void): void { | ||
if (!this.callbacks[key]) | ||
this.callbacks[key] = []; | ||
this.callbacks[key].push(callback); | ||
} | ||
|
||
private sendMessage(data: any): void { | ||
if (!this.nativeElement.contentWindow) | ||
throw new Error('Native element does not have a content window'); | ||
|
||
this.nativeElement.contentWindow.postMessage(data, '*'); | ||
} | ||
|
||
private registerEventListeners(): void { | ||
this.registerEventListener('elfsquad.visualization.screenshotTaken', (event: MessageEvent) => { | ||
this.executeCallbacks(ViewerEvent.ScreenshotTaken, event.data.args); | ||
}); | ||
|
||
window.addEventListener('message', (event: MessageEvent) => { | ||
try { | ||
const json = JSON.parse(event.data); | ||
if (json.action !== "createQuotation") | ||
return; | ||
|
||
const configurationId = json.argument; | ||
this.executeCallbacks(ViewerEvent.RequestQuote, { configurationId }); | ||
} catch (e) { | ||
return; | ||
} | ||
}); | ||
} | ||
|
||
private registerEventListener(key: string, callback: (data: MessageEvent) => void): void { | ||
window.addEventListener('message', (event: MessageEvent) => { | ||
if (event.data?.name === key) | ||
callback(event); | ||
}); | ||
} | ||
|
||
private executeCallbacks(key: ViewerEvent, data: any): void { | ||
if (!this.callbacks[key]) | ||
return; | ||
|
||
this.callbacks[key].forEach(callback => { | ||
callback(data); | ||
}); | ||
} | ||
|
||
private render(options: ElfsquadShowroomOptions): HTMLIFrameElement { | ||
const iframe = document.createElement('iframe'); | ||
iframe.src = options.url; | ||
iframe.style.width = '100%'; | ||
iframe.style.height = '100%'; | ||
iframe.style.border = 'none'; | ||
iframe.style.margin = '0'; | ||
iframe.style.padding = '0'; | ||
iframe.style.display = 'block'; | ||
this.container.appendChild(iframe); | ||
return iframe; | ||
} | ||
|
||
private getContainer(options: ElfsquadShowroomOptions): HTMLElement { | ||
if (typeof options.container === 'string') { | ||
const ret = document.querySelector(options.container); | ||
if (ret === null) | ||
throw new Error('Container not found'); | ||
if (!(ret instanceof HTMLElement)) | ||
throw new Error('Container must be an HTMLElement'); | ||
return ret; | ||
} | ||
return options.container; | ||
} | ||
} | ||
|
Oops, something went wrong.