cloudinary-8.x-1.x-dev/modules/cloudinary_media_library_widget/js/cloudinary_media_library.form.js
modules/cloudinary_media_library_widget/js/cloudinary_media_library.form.js
(function ($, Drupal, once, drupalSettings, cloudinary) {
'use strict';
/**
* Defines a behaviour to handle custom cloudinary form element.
*/
Drupal.behaviors.cloudinaryMediaLibraryFormElement = {
attach: function (context) {
const self = this;
const settings = drupalSettings.cloudinary_media_library || false;
if (!settings) {
console.error('No settings available for cloudinary elements.');
return;
}
const widgetSettings = settings.base;
const elementsWidgetSettings = settings.elements;
once('cloudinaryMediaLibrary', $(context).find('input.form-cloudinary')).forEach(function (input) {
const $input = $(input);
const elementSettings = elementsWidgetSettings[$input.closest('fieldset').attr('id')];
const hasPreview = $input.hasClass('has-preview');
const multiple = elementSettings.multiple;
// Build preview based on default value.
if ($input.val().length && hasPreview) {
const preview = multiple
? self.buildMultiplePreviewByInput(input)
: self.buildPreviewImageByInput(input);
$input.before(preview);
}
// Build open media button.
$input.after('<div class="js-cloudinary-button-wrapper"><button class="button cloudinary-media-library-button">' + Drupal.t('Open media library', {}, { context: 'Cloudinary media' }), + '</button></div>');
$input.parent().find('.cloudinary-media-library-button').on('click', function (e) {
e.preventDefault();
// Display loading spinner.
$input.after($(Drupal.theme('ajaxProgressThrobber')));
const options = {
cloud_name: widgetSettings.cloud_name,
api_key: widgetSettings.api_key,
use_saml: widgetSettings.use_saml || false,
multiple: multiple,
max_files: elementSettings.max_files,
button_caption: Drupal.t('Open media library', {}, { context: 'Cloudinary media' }),
button_class: 'button cloudinary-media-library-button',
insert_caption: Drupal.t('Insert', {}, { context: 'Cloudinary media' }),
folder: {
resource_type: $input.data('resource-type'),
}
};
if (widgetSettings.starting_folder) {
options.folder.path = widgetSettings.starting_folder;
}
// Better support of files including PDF files.
if ($input.data('resource-type') === 'raw') {
delete options.folder;
options.search = {
expression: 'resource_type:raw OR format=pdf'
};
}
const handlers = {
insertHandler: function (data) {
if (!this.input) {
console.error('Cloudinary input element not found.');
return;
}
const $input = $(this.input);
// Trigger add asset button automatically once the input was populated.
$input.on('change', function () {
$(this).closest('.js-form-cloudinary-container')
.find('.add-asset-button')
.trigger('mousedown');
});
// Collect multiple value from all the assets.
const values = [];
data.assets.forEach(function (asset) {
const context = asset.context || {};
const metadata = context.custom || {};
const transformation = [];
if (typeof asset.derived !== 'undefined') {
for (let i = 0; i < asset.derived.length; i++) {
transformation.push(asset.derived[i].raw_transformation);
}
}
const titleAttribute = widgetSettings.default_title_attribute;
const descriptionAttribute = widgetSettings.default_description_attribute;
let title = '';
let description = '';
if (titleAttribute === 'context.custom.caption') {
title = metadata.caption || '';
}
else {
title = asset.metadata[titleAttribute] || '';
}
if (descriptionAttribute === 'context.custom.alt') {
description = metadata.alt || '';
}
else {
description = asset.metadata[descriptionAttribute] || '';
}
const value = [
'cloudinary',
asset.resource_type,
asset.type,
asset.public_id,
transformation.join('/')
].filter(value => value.length).join(':');
values.push({
value: value,
alt: description,
title: title
});
// Nothing to do more for multiple items.
if (multiple) {
return;
}
$input.val(value);
const $wrapper = $input.closest('.form-item').parent();
if ($wrapper.find('.form-asset-item--alt').length) {
$wrapper.find('.form-asset-item--alt').val(description);
}
if ($wrapper.find('.form-asset-item--title').length) {
$wrapper.find('.form-asset-item--title').val(title);
}
if (hasPreview) {
const previewImage = self.buildPreviewImageByAsset(asset);
const $oldPreview = $input.parent().find('.cloudinary-preview');
if ($oldPreview.length) {
$oldPreview.remove();
}
$input.before('<div class="cloudinary-preview">' + previewImage + '</div>');
}
$input.trigger('change');
});
// Store multiple values as a json string.
if (multiple) {
$input.val(JSON.stringify(values));
if (hasPreview) {
const preview = self.buildPreviewWithMultipleAssets(data.assets);
const $oldPreview = $input.parent().find('.cloudinary-preview');
if ($oldPreview.length) {
$oldPreview.remove();
}
$input.before(preview);
}
$input.trigger('change');
}
},
showHandler: function () {
const input = this.input;
if (!input) {
console.error('Cloudinary input element not found.');
return;
}
// Delete ajax progress spinner.
const spinner = input.parentElement.querySelector('.ajax-progress');
if (spinner) {
spinner.remove();
}
}
};
const element = cloudinary.openMediaLibrary(options, handlers);
element.input = $(this).closest('.js-form-item').find('input')[0];
});
});
},
buildPreviewImageByInput: function (input) {
const imageUrl = input.dataset.previewImage;
if (typeof imageUrl === 'undefined') {
return '';
}
return '<div class="cloudinary-preview"><img loading="lazy" width="200" alt="Preview image" src="' + imageUrl + '"></div>';
},
buildMultiplePreviewByInput: function (input) {
const assets = [];
const values = JSON.parse(input.value);
const preview = JSON.parse(input.dataset.preview);
for (let i = 0; i < values.length; i++) {
const value = values[i];
const asset = {
public_id: value.public_id,
previewImageUrl: preview[i] || null,
context: {
custom: {
caption: value.title || null,
alt: value.alt || null
}
},
};
assets.push(asset);
}
return this.buildPreviewWithMultipleAssets(assets);
},
buildPreviewWithMultipleAssets: function (assets) {
let output = '';
for (let i = 0; i < assets.length; i++) {
const asset = assets[i];
const context = asset.context || {};
const metadata = context.custom || {};
const imageAlt = metadata.alt || 'Preview image';
const imageTag = typeof asset.previewImageUrl !== 'undefined'
? asset.previewImageUrl ? '<img loading="lazy" width="100" alt="' + imageAlt + '" src="' + asset.previewImageUrl + '">' : ''
: this.buildPreviewImageByAsset(asset, 100);
output += '<div>' + imageTag + '<div>';
if (metadata.caption) {
output += '<p>' + metadata.caption + '</p>';
}
if (metadata.alt) {
output += '<p>' + metadata.alt + '</p>';
}
output += '<p><strong>' + asset.public_id + '</strong></p>';
output += '</div></div>';
}
return '<div class="cloudinary-preview">' + output + '</div>'
},
buildPreviewImageByAsset: function (asset, width) {
// No preview images available for raw files.
if (asset.resource_type === 'raw') {
return '';
}
let imageUrl = asset.secure_url;
let alt = asset.public_id;
if (asset.context && asset.context.custom && asset.context.custom.alt) {
alt = asset.context.custom.alt;
}
// Get thumbnail from video or PDF.
if (asset.resource_type === 'video' || (asset.resource_type === 'image' && asset.format === 'pdf')) {
imageUrl = imageUrl.replace('.' + asset.format, '.jpeg');
}
// Crop image by 400px to improve performance.
const splitter = '/' + asset.resource_type + '/' + asset.type;
const urlParts = imageUrl.split(splitter);
width = width || 200;
const rawTransformation = ['c_fill,w_' + width * 2];
if (typeof asset.derived !== 'undefined') {
for (let i = 0; i < asset.derived.length; i++) {
rawTransformation.push(asset.derived[i].raw_transformation);
}
}
imageUrl = urlParts[0] + splitter + '/' + rawTransformation.join('/') + urlParts[1];
return '<img loading="lazy" width="' + width + '" alt="' + alt + '" src="' + imageUrl + '">';
}
};
})(jQuery, Drupal, once, drupalSettings, cloudinary);
