import React from "react" import ContentstackSDK from "@contentstack/app-sdk" import { ImageElement } from "~/components/ImageElement" import { Icon } from "@contentstack/venus-components" import { openImageVault } from "~/utils/imagevault" import type { Lang } from "~/types/lang" import type { ContentstackEmbeddedData, ContentstackPluginDefinition, ExtractedContentstackEmbeddedData, } from "~/types/contentstack" function findThisPlugin(ext: ContentstackPluginDefinition) { return ext.type === "rte_plugin" && ext.title === "ImageVault" } async function loadScript(url: string) { return new Promise((resolve, reject) => { if (!document) { throw new Error("Run in browser only") } const head = document.head || document.getElementsByTagName("head")[0] const script = document.createElement("script") script.type = "text/javascript" script.async = true script.src = url script.onload = function () { this.onerror = this.onload = null resolve(window.ImageVault) } script.onerror = function () { this.onerror = this.onload = null reject(`Failed to load ${this.src}`) } head.appendChild(script) }) } function extractContentstackEmbeddedData( jwtLike: string ): ExtractedContentstackEmbeddedData | null { try { const base64str = jwtLike.replace(/-/g, "+").replace(/_/g, "/") const jsonStr = decodeURIComponent( window .atob(base64str) .split("") .map(function (c) { return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2) }) .join("") ) const json = JSON.parse(jsonStr) json.exports = JSON.parse(json.exports) json.props.value = JSON.parse(json.props.value) if (IS_DEV) { console.log(`Contentstack Embedded Data`, json) } const { entryMetadata, utilis: { content_type: { schema }, extensions, }, requestProps: { stack: { api_key }, branch, }, }: ContentstackEmbeddedData = json.props.value const titleField = schema.find((f) => f.uid === "title") // We force this value with ! because we know it exists. // Otherwise this code would not run. const plugin = extensions.find(findThisPlugin)! return { stack: { apiKey: api_key, }, branch, contentType: { uid: entryMetadata.contentTypeUid, }, entry: { locale: entryMetadata.locale, title: titleField && titleField.data_type === "text" ? titleField.value : "Untitled", uid: entryMetadata.entryUid, }, plugin, } } catch (e) { console.log(`Unable to parse JWT like: ${jwtLike}`) } return null } let ivloaded = false function loadIV(plugin: ContentstackPluginDefinition) { if (plugin.src) { const url = new URL(plugin.src) url.pathname = "/scripts/imagevault-insert-media/insertmediawindow.min.js" if (IS_DEV) { console.log(`Loading script: ${url.toString()}`) } loadScript(url.toString()) ivloaded = true } } async function init() { try { const sdk = await ContentstackSDK.init() const extensionObj = sdk?.location const RTE = extensionObj?.RTEPlugin let embeddedData: ExtractedContentstackEmbeddedData | null = null const jwtLike = window.name.split("__").find((str) => str.startsWith("ey")) if (jwtLike) { embeddedData = extractContentstackEmbeddedData(jwtLike) if (embeddedData?.plugin) { loadIV(embeddedData.plugin) } } if (!RTE) return const ImageVault = RTE("ImageVault", (rte) => { if (rte) { if (!ivloaded) { // Loading failed via embedded data above, try again with data inside RTE // @ts-expect-error: incorrect typings, requestProps is available at runtime const extensions = rte._adv.editor.requestProps .extensions as ContentstackPluginDefinition[] const plugin = extensions.find(findThisPlugin) if (plugin) { loadIV(plugin) } } } return { title: "Choose assets from ImageVault", icon: , render: (props) => { if (rte) { return ( {props.children} ) } else { console.error("No instance of RTE found") return (

An unexpected error occured, see console for more info.

) } }, display: ["toolbar"], elementType: ["void"], } }) ImageVault.on("exec", async (rte) => { if (rte) { const savedSelection = rte?.selection?.get() ?? undefined // @ts-expect-error: Added at runtime const appConfig = await rte.getConfig() // This is the configuration for this instance of the plugin. // You edit this in the content types settings RTE plugin section. // @ts-expect-error: Added at runtime const pluginConfig = await rte.getFieldConfig() const config = { ...appConfig, ...pluginConfig, } openImageVault({ config, entryData: { //TODO: Add support for branches branch: embeddedData ? embeddedData.contentType.uid : "main", contentTypeUid: embeddedData ? embeddedData.contentType.uid : "Unknown", locale: embeddedData ? embeddedData.entry.locale : ("unknown" as Lang), stackApiKey: embeddedData ? embeddedData.stack.apiKey : "unknown", title: embeddedData ? embeddedData.entry.title : "Untitled", uid: embeddedData ? embeddedData.entry.uid : "unknown", }, onSuccess(result) { rte.insertNode( { // @ts-expect-error: incorrect typings type: "ImageVault", attrs: result, uid: crypto.randomUUID(), children: [{ text: "" }], }, { at: savedSelection } ) }, }) } }) return { ImageVault, } } catch (e) { console.error({ e }) } } export default init()