You can use this plugin to browse through images that either can be organized into subfolders or into one big folder. This plugin also has some basic image editing features built in as well.
With this you can open a gallery from our Email editor or Variable editor plugin with their hooks.
You can initialize this plugin with the following function call:
const galleryConfig = {
plugin: "gallery",
data: {
currentImgSrc, // The current image
dimensions, // Fixed image dimensions.
},
settings: {
hideHeader: false, // hides the header
folderTree: {
_id: root,
name: "Root folder",
children: [{}],
}, // Object following the folder structure you want to use, every folder has an _id and a name. The optional children array contains the subfolder objects.
selectedFolderId: "root", // The _id of the currently selected folder.
maxImagePerPage: 12, // Set the number of images
maxFileSize: 5, // Set the maximum size of uploadable images in Megabytes
panels: {
stockPhotos: true, // enable or disable the stock photos tab
},
uploadOptions: {
url: true, // enable or disable upload via url
file: true, // enable or disable file upload
},
},
hooks: {}, // an object of available hooks (for example onFolderSelected)
};
// Fullscreen
const galleryInstance = await chamaileonPlugins.createFullscreenPlugin(galleryConfig);
// Inline
const galleryInstance = await chamaileonPlugins.createInlinePlugin(
galleryConfig,
{
container: "#gallery", /* HTML Element */
dimensions: {
width: 1000, // default 100%
height: 720, // default 100%
scale: 1, // default 1
}
}
);
These will be returned after a successful plugin initialization.
These are methods provided by the plugin instance.
Updates the settings inside the plugin instance on the fly.
const newSettings = {
maxImagePerPage: 15,
selectedFolderId: "otherFolderId",
}
await galleryInstance.methods.updateSettings(newSettings);
Updates the data inside the plugin instance on the fly.
await galleryInstance.methods.updateData({ editImgSrc, dimensions });
Updates the hooks inside the plugin instance on the fly.
You can read more about the updateHooks
method here.
await galleryInstance.methods.updateHooks({ hooks, resetHooks });
Returns the src of the image that was selected inside the gallery. You can await this method right after the plugin is initialized or updated and it will return a Promise
that will be resolved if the user choses an image.
const { src } = await galleryInstance.methods.pickImage();
Shows the preview instance iframe. Fullscreen mode only.
You can read more about the optionalParams
object here.
await galleryInstance.show(optionalParams);
Hides the preview instance iframe. Fullscreen mode only.
await galleryInstance.hide();
Shows the splash screen inside the preview instance. Fullscreen mode only.
await galleryInstance.showSplashScreen();
Hides the splash screen inside the preview instance. Fullscreen mode only.
galleryInstance.hideSplashScreen();
Destroys the preview instance.
await galleryInstance.destroy();
Property | Type | Description |
---|---|---|
data | object | The initial data of the plugin instance |
settings | object | The initial settings of the plugin instance |
hooks | object | You can register callbacks on multiple events coming from the plugin. For more, please check out the galleryConfig.hooks section. |
The data object has the following properties:
Property | Type | Description |
---|---|---|
currentImgSrc | object | The current image src. |
dimensions | object | You can fix the returned image dimensions with this parameter. |
Property | Type | Description |
---|---|---|
width | integer | The fixed image width. |
height | integer | The fixed image height. |
The settings object has the following properties:
Property | Type | Description |
---|---|---|
folderTree | object | To organize the image assets in a user-friendly way. |
selectedFolderId | string | With Folder Tree defined, you can specify which folder will be the default for the gallery instance. The Gallery will start a request to fetch images from this folder at the initialization. |
maxImagePerPage | number | The gallery uses infinite scrolling as pagination, and you can decide how many pictures are loaded for a single request. The default is 12. |
maxFileSize | number | With default 5 MB, you can alter the maximum file size (in megabytes) users can upload to your server. The field requires a number as a value. |
panels | object | Object that configures panel visibility (hidden or visible) |
uploadOptions | object | Object that configures upload option visibility (hidden or visible) |
You can control the visibility state of our panels.
Currently only the Stock photos
panel can be changed.
Example:
galleryConfig.settings.panels = {
stockPhotos: false,
};
You can control the visibility state of our upload options.
Example:
galleryConfig.settings.uploadOptions = {
url: false,
file: true,
};
The folder tree is designed to help with the organization of image assets in a user-friendly way. It's recommended to follow the folder tree structure of your emails.
Each folder has the following properties:
Property | Type | Description |
---|---|---|
_id | string | The _id of the folder. |
name | string | The name of the folder. |
children | array | An array containing the subfolder objects. |
canCreateSubfolder | boolean | If true, the user will be able to create subfolders inside this folder. If false or missing, the subfolder creation is disabled. |
canRename | boolean | If true, the user will be able to rename this folder. If false or missing, the folder cannot be renamed. This parameter does not apply to the root folder. |
canDelete | boolean | If true, the user will be able to delete this folder. If false or missing, the folder cannot be deleted. This parameter does not apply to the root folder. |
canDeleteImages | boolean | If true or missing, the user will be able to delete an image in this folder. If false, the images in the folder cannot be deleted. |
canEditImages | boolean | If true or missing, the user will be able to edit an image in this folder. If false, the images in the folder cannot be edited. |
canCropImages | boolean | If true or missing, the user will be able to crop an image in this folder. If false, the images in the folder cannot be cropped. |
canRenameImages | boolean | If true or missing, the user will be able to rename an image in this folder. If false, the images in the folder cannot be renamed. |
Example:
galleryConfig.settings.folderTree = {
_id: "root",
name: "Root folder",
canCreateSubfolder: true,
children: [
{
_id: "021548489999",
name: "Favorite Images",
canCreateSubfolder: true,
canRename: true,
canDelete: false,
canDeleteImages: true,
canEditImages: true,
canCropImages: true,
canRenameImages: true,
},
],
};
Each and every hook should be an asynchronous process, so all of the hook handler functions have to return Promise
s.
In most cases you just have to resolve the promise when the async operation is done without any params, but in some cases, you will have to resolve certain objects with properties that the plugin can use. Similarly to the parameters, we always expect an object to be resolved, even if it only has one property. (This way it will be easier to add new properties later on if needed.)
If any errors occurred on your side, you can reject the promise with an instance of Error
. In this case, the error message will be shown in a snackbar inside the plugin instance.
function handler(params) {
return new Promise((resolve, reject) => {
// You can put the logic here.
// Resolve the promise when everything is okay
// Reject the promise on error
if (!error) {
resolve(dataToResolve) // In some cases, you don't have to resolve any data. You can resolve the promise without a parameter.
} else {
reject(new Error("Your error message"))
}
})
}
Note that, with the async syntax, the unexpected errors will be also displayed:
async function handler(params) {
// Unexpected errors will also cause promise rejections in this case
// For example, if you get a timeout error, that will also be displayed in a snackbar in the editor.
// Any exception will be caught by the SDK and the message property of the error object will be shown in a snackbar.
return dataToResolve;
}
Below are the list of hooks that you can use. Read more about them in the following sections.
galleryConfig.hooks = {
close,
onUploadImage,
onSaveUrl,
onUpdateImage,
onDeleteImage,
onFolderSelected,
onCreateSubfolder,
onRenameFolder,
onDeleteFolder,
};
This hook is called when the top left back arrow button is clicked. You should hide the plugin with this and you can also implement a custom logic that runs after the plugin is hidden.
/*
Params: nothing.
Has to resolve: nothing.
*/
galleryConfig.hooks.close = () => {
return new Promise(resolve => {
galleryInstance.hide();
resolve();
});
};
There are a few cases when this function is invoked. The first one is right after the initialization, the second case is when someone selects a folder, the third is when someone searches for an image in the folder and the fourth is when the user scrolls down through the images and more of them needs to be loaded.
Based on the parameters of this function, you can fetch the corresponding data from your backend, and resolve it as an object that contains the images array and the count of the query.
/*
Params:
- selectedFolderId: current folder id.
- parents: returns an array that contains every parent of the current folder
- searchValue: search string from the search input.
- orderValue: in which order are the images currently sorted.
- maxImagePerPage: maximum number of images in a single page.
- pageNumber: current page number inside the gallery.
Has to resolve:
- images: an array with objects that contain the image information
- each object has to contain:
- name
- src
- _id
- count: the maximum number of images that match every criteria provided in the parameters
*/
galleryConfig.hooks.onFolderSelected = ({
selectedFolderId, parents, searchValue, orderValue, maxImagePerPage, pageNumber,
}) => {
return new Promise(resolve => {
// you can put the logic here that filters, orders and fetches the images.
// when it's done, you can resolve the promise.
resolve({ images, count });
});
};
This function is called when an image is uploaded or when a stock photo is chosen to be saved.
The image is encoded to Base64 format. If you want to convert it to a binary format, this is the place where you can do that before sending it to your backend.
/*
Params:
- selectedFolderId: current folder id.
- parents: returns an array that contains every parent of the current folder
- image:
- data: Base64 encoded image data
- name: image name
Has to resolve:
- image: the final image object with _id, name and src fields
*/
galleryConfig.hooks.onUploadImage = ({ selectedFolderId, parents, image }) => {
return new Promise(resolve => {
// you can put the logic here that saves the image in your database.
// when it's done, you can resolve the promise.
resolve({ _id, name, src });
});
};
This function is called when an image is saved from an URL. In this case we send the plain URL instead of the encoded image data.
/*
Params:
- selectedFolderId: current folder id.
- parents: returns an array that contains every parent of the current folder
- image:
- url: image url
- name: image name
Has to resolve:
- image: the final image object with _id, name and src fields
*/
galleryConfig.hooks.onSaveUrl = ({ selectedFolderId, parents, image }) => {
return new Promise(resolve => {
// you can put here the logic to save the image url in your database
// and when it's done, you can resolve the promise.
resolve({ _id, name, src });
});
};
This function is called when an image title is changed inside the plugin.
/*
Params:
- imageId: the id of the updated image
- selectedFolderId: current folder id.
- parents: returns an array that contains every parent of the current folder
- image:
- data: image url
- name: image name
Has to resolve: nothing.
*/
galleryConfig.hooks.onUpdateImage = ({ imageId, parents, selectedFolderId, image }) => {
return new Promise(resolve => {
// you can put the logic here to save the new title.
resolve();
});
};
This function is called when an image is deleted inside the plugin.
/*
Params:
- imageId: the id of the updated image
- selectedFolderId: current folder id.
- parents: returns an array that contains every parent of the current folder
Has to resolve: nothing.
*/
galleryConfig.hooks.onDeleteImage = ({ imageId, parents, selectedFolderId }) => {
return new Promise(resolve => {
// you can put the logic here that deletes the image from your backend.
resolve();
});
};
This function is called when a subfolder is created inside the plugin.
/*
Params:
- selectedFolderId: the id of the folder in which the user created a subfolder
- name: the name of the new subfolder
- parents: returns an array that contains every parent of the current folder
Has to resolve:
- _id: the id of the new subfolder
- name: the name of the new subfolder (it can differ from the one given in the params)
- canCreateSubfolder: true if the users will be able to create subfolders inside the new folder. Defaults to false
- canRename: true if the users will be able to rename the new folder. Defaults to false
- canDelete: true if the users will be able to delete the new folder. Defaults to false
*/
galleryConfig.hooks.onCreateSubfolder = ({ selectedFolderId, name, parents }) => {
return new Promise(resolve => {
// you can put the logic here that creates a subfolder.
resolve();
});
};
This function is called when a folder is renamed inside the plugin.
/*
Params:
- selectedFolderId: the id of the folder
- name: the new name of the folder
- parents: returns an array that contains every parent of the current folder
Has to resolve:
- name: the new name of the folder (it can differ from the one given in the params)
*/
galleryConfig.hooks.onRenameFolder = ({ selectedFolderId, name, parents }) => {
return new Promise(resolve => {
// you can put the logic here that saves the new folder name.
resolve();
});
};
This function is called when a folder is deleted inside the plugin.
/*
Params:
- selectedFolderId: the id of the folder
- parents: returns an array that contains every parent of the current folder
Has to resolve: nothing.
*/
galleryConfig.hooks.onDeleteFolder = ({ selectedFolderId, parents }) => {
return new Promise(resolve => {
// you can put the logic here that deletes the folder.
resolve();
});
};
You need to enable CORS headers on the image sources that you will use inside the plugin. It's needed because we have to fetch the full image data and without the CORS headers present it will throw an error. When these headers are not present on the image source we will use a fallback proxy route but it can cause some delays with the loading.
The gallery supports the PhotoEditor SDK extension with advanced image editing features. Please contact us if you are interested.
const editorInstance = await chamaileonPlugins.createFullscreenPlugin({
plugin: "editor",
data: {},
settings: {},
hooks: {
onEditImage: async ({ originalImage, lockDimensions }) => {
galleryInstance.methods.updateData({ currentImgSrc: originalImage, dimensions: lockDimensions });
galleryInstance.show();
const { src } = await galleryInstance.methods.pickImage();
galleryInstance.hide();
return { src };
},
onEditBackgroundImage: async ({ originalImage }) => {
galleryInstance.methods.updateData({ currentImgSrc: originalImage, dimensions: null });
galleryInstance.show();
const { src } = await galleryInstance.methods.pickImage();
galleryInstance.hide();
return { src };
},
},
});
const variableEditorInstance = await chamaileonPlugins.createFullscreenPlugin({
plugin: "variable-editor",
data: {},
settings: {},
hooks: {
onEditImage: async () => {
galleryInstance.methods.updateData({ currentImgSrc: "", dimensions: null });
galleryInstance.show();
const { src } = await galleryInstance.methods.pickImage();
galleryInstance.hide();
return { src };
},
},
});
You can also check out the gallery plugin on the Chamaileon SDK Playground.