Gallery Plugin

You can initialize the gallery plugin from the Email Editor plugin, through the editImage hook. The hook has to return a promise which will be resolved in the gallery plugin with the value of the selected image source.

The gallery is not just for previewing, but to use basic editing features. You can connect the gallery to any database and storage solution of your choice.

To the initializing function (openGallery), you have to pass a config object. The config object's properties are detailed later in this section.

const galleryConfig = {
    editImgSrc: originalImage, // The current image
    dimensions: lockDimensions, // Editor Block Lock addon provided dimensions to fix the image aspect ratio.
    imageEditor // 3rd party image editor settings
    settings: {
        folderTree: {
            _id: root,
            name: "Root folder",
            children: [{}], 
        },
        // Object following the folder structure you want to use, all folder has an _id and name. Optional children field contains the child folder objects.
        selectedFolderId: "root", // The _id of the folder to select on Init.
        maxImagePerPage: 12, // Set the number of images
        maxFileSize: 5, // Set the maximum size of uploadable images in Megabytes
    },
    hooks: {} // an object of available hooks (for example onSave)
};
const editorInstance = await chamaileonPlugins.editEmail(galleryConfig);

Gallery configuration

As the editor itself is, the gallery configuration happens trought the config object you pass to the openGallery function. It has the following properties:

Property Type Description
editImgSrc string The url of the current image in the Editor plugin opened to edit.
dimensions object Contains the width and height fields of the current image inside a designed lock block.
imageEditor object 3rd party Image Editor configuration
settings object The settings of the gallery instance.
hooks object You can register callbacks on multiple events coming from the gallery. For more, please check out the galleryConfig.hooks section.

galleryConfig.settings

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.
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.

galleryConfig.settings.folderTree

Inside the settings field, you can add a tree structure to the Gallery.

Each folder has a maximum of 3 fields, name, _id, children. The first two are strings and the last is an array possible with other folder objects. The Folder Tree is designed to organize the image assets in a user-friendly way. It is recommended to follow the structure of the Folder Tree of emails.

Example:

galleryConfig.settings.buttons.header = [
folderTree: {
    _id: root,
    name: "Root folder",
    children: [{
        _id: "021548489999",
        name: "Favorite Images",
    }],         
}

galleryConfig.hooks

Like in the editor each and every hook is supposedly an asynchronous process, so all of the hook handler functions have to return Promises.

For example, when a user clicks on the save button, a load indicator will start spinning, and the onSave hook is called. Until the promise is not resolved, the loading indicator will continue spinning.

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 editor 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 in the editor.

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 catched by the SDK and the message property of the error object will be shown in a snackbar.
    return dataToResolve
}

You can see below the hooks you can use. Read more about them in the following sections.

galleryConfig.hooks = {
  onFolderSelected,
};

galleryConfig.hooks.onFolderSelected

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, and the third is when someone searches for an image in the folder.

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, parents, searchValue, orderValue, maxImagePerPage, pageNumber }).

Has to resolve: images object, contains the images array and the count of the the total items in the folders.

The images array each item has to contain the following: _id, name and src attribute.
*/

galleryConfig.hooks.onFolderSelected = ({ selectedFolderId, parents, searchValue, orderValue, maxImagePerPage, pageNumber }) => {
    return new Promise(resolve => {
        // you can put here the logic that filter, order and fetch the images for the request.
        // and when it's done, you can resolve the promise.
        resolve({ images, count });
    });
};

galleryConfig.hooks.onUploadImage

This function is called when one image is uploaded, included when a stock photo is chosen to be saved.

The image is encoded to Base64 format. If you choose to convert it to binary format, this is the place where you can do that before sendig it to your backend.

/*
Params:
({ selectedFolderId, parents, image }).

Has to resolve: an image object (the saved image) contains the following: _id, name and src attribute.
*/

galleryConfig.hooks.onUploadImage = ({ selectedFolderId, parents, image }) => {
    return new Promise(resolve => {
        // you can put here the logic to save the image in your database
        // and when it's done, you can resolve the promise.
        resolve({ _id, name, src });
    });
    };

galleryConfig.hooks.onSaveUrl

This function is called when an image is saved as an URL, in this case, we send the URL on the image object, not data.
Works the same way as the onImgaeUpload function and return also an image object with _id, name and src attribute.

/*
Params:
({ selectedFolderId, parents, image }).

Has to resolve: an image object (the saved image) contains the following: _id, name and src attribute.
*/

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 });
    });
};

galleryConfig.hooks.onUpdateImage

This function is called when an image title is changed in the Gallery.

/*
Params:
({ imageId, parents, selectedFolderId, image }).

Has to resolve: nothing.
*/

galleryConfig.hooks.onUpdateImage = ({ imageId, parents, selectedFolderId, image }) => {
    return new Promise(resolve => {
        // you can put here the logic to save the new title.
        resolve();
    });
};

galleryConfig.hooks.onDeleteImage

This function is called when an image is deleted.

/*
Params:
({ imageId, parents, selectedFolderId }).

Has to resolve: nothing.
*/

galleryConfig.hooks.onDeleteImage = ({ imageId, parents, selectedFolderId }) => {
    return new Promise(resolve => {
        // you can put here the logic to delete the image from your backend.
        resolve();
    });
};

Connect the Gallery to the editor instance

As a reminder, you can define your own Gallery calling function inside the editorConfig.hooks.onEditImage and editorConfig.hooks.onEditBackgroundImage hooks. This function has to resolve the image object with a "src" field to paste the image in the editor. In the example below the openGallery function is already defined and called with the right parameters from editorConfig.hooks.onEditImage hook.

The openGallery function itself returns a promise with the resolved value of the image object and the src field you need. Practically, you can directly return this awaited function.

/*
Params:
 - originalImage: optional, string, shows that a user wants to edit an image
 - lockDimensions: optional, object, you have to crop the image to this aspect ratio
    - width
    - height

Has to resolve:
 - src
*/
editorConfig.hooks.onEditImage = ({ originalImage, lockDimensions: { width, height } }) => {
    const { src }  = await this.openGallery( { editImgSrc: originalImage, dimensions: lockDimensions });
    // Eventually, you will have to resolve an object with a src prop
    return { src };
};

About CORS

You have to handle cross-origin requests. To allow scripts to get the content of an image the Access-Control-Allow-Origin header has to be added to the response.
For cases when its not present we use proxying, but in this case, you can expect some delay at loading.

Extra plugins

The gallery supports PhotoEditor SDK for more advanced editing features. Please contact us if you interested.

Examples

You can also check out the gallery plugin on the Chamaileon SDK Playground.