@getgreenspark/widgets
Version:
An SDK design to help the use of Greenspark's widget API in the browser
66 lines (56 loc) • 2.13 kB
text/typescript
import { DEFAULT_CONTAINER_CSS_SELECTOR } from '@/constants'
export class DOMInjector {
containerSelector: string
useShadowDom?: boolean
constructor({
containerSelector,
useShadowDom = true,
}: {
containerSelector: string
useShadowDom?: boolean
}) {
this.containerSelector = containerSelector
this.useShadowDom = useShadowDom
}
getWrapper(container: Element): ShadowRoot | Element {
if (!this.useShadowDom) {
return container
}
return container.shadowRoot ?? container.attachShadow({ mode: 'open' })
}
inject(widget: HTMLElement, containerSelector?: string) {
if (!widget) return
this.containerSelector = containerSelector ?? this.containerSelector
const container = document.querySelector(this.containerSelector)
if (!container) {
throw new Error(
`Greenspark - The document.querySelector('${this.containerSelector}') does not return an Element. Are you sure that you input the correct 'containerSelector'? The default selector is ${DEFAULT_CONTAINER_CSS_SELECTOR}`,
)
}
container.setAttribute('data-greenspark-shadow-dom-container', 'true')
const scripts = [...widget.children].filter((el) => el.tagName === 'SCRIPT')
const nonScripts = [...widget.children].filter((el) => el.tagName !== 'SCRIPT')
const wrapper = this.getWrapper(container)
while (wrapper.firstChild) {
wrapper.removeChild(wrapper.firstChild)
}
wrapper.append(...nonScripts)
if (document.readyState === 'complete' || document.readyState === 'interactive') {
scripts.forEach((s) => eval(s.innerHTML))
} else {
document.addEventListener('DOMContentLoaded', function () {
scripts.forEach((s) => eval(s.innerHTML))
})
}
}
parseHtml(html: string): HTMLElement {
const parser = new DOMParser()
const parsedWidget = parser.parseFromString(html, 'text/html')
if (parsedWidget.body === null) {
throw new Error(
`Greenspark - An error occurred when trying to execute 'renderToElement'. Failed to render ${html} `,
)
}
return parsedWidget.body
}
}