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" && /imagevault/i.test(ext.title)
}
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:
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, FocalPoint: result.FocalPoint || { x: 50, y: 50 }, }, uid: crypto.randomUUID(), children: [{ text: "" }], }, { at: savedSelection } ) }, }) } }) return { ImageVault, } } catch (e) { console.error({ e }) } } export default init()