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:
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();