import {CloudinaryImage} from "@cloudinary/url-gen/assets/CloudinaryImage";
import {Plugin, HtmlPluginState, BaseAnalyticsOptions, AnalyticsOptions, PluginResponse} from "../types";
import {scale} from "@cloudinary/url-gen/actions/resize";
import debounce from 'lodash.debounce';
import {isNum} from '../utils/isNum';
import {isBrowser} from "../utils/isBrowser";
import {Action} from "@cloudinary/url-gen/internal/Action";
import {isImage} from "../utils/isImage";
import {getAnalyticsOptions} from '../utils/analytics'
export function responsive({steps}:{steps?: number | number[]}={}): Plugin{
return responsivePlugin.bind(null, steps);
}
function responsivePlugin(steps?: number | number[], element?:HTMLImageElement, responsiveImage?: CloudinaryImage, htmlPluginState?: HtmlPluginState, baseAnalyticsOptions?: BaseAnalyticsOptions): Promise<PluginResponse> | boolean {
if(!isBrowser()) return true;
if(!isImage(element)) return;
return new Promise((resolve)=>{
htmlPluginState.cleanupCallbacks.push(()=>{
window.removeEventListener("resize", resizeRef);
resolve('canceled');
});
const analyticsOptions = getAnalyticsOptions(baseAnalyticsOptions, {responsive: true});
responsiveImage.addAction(new Action().setActionTag('responsive'));
onResize(steps, element, responsiveImage, analyticsOptions);
let resizeRef: any;
htmlPluginState.pluginEventSubscription.push(()=>{
window.addEventListener('resize', resizeRef = debounce(()=>{
onResize(steps, element, responsiveImage, analyticsOptions);
}, 100));
});
resolve({responsive: true});
});
}
function onResize(steps?: number | number[], element?:HTMLImageElement, responsiveImage?: CloudinaryImage, analyticsOptions?: AnalyticsOptions){
updateByContainerWidth(steps, element, responsiveImage);
element.src = responsiveImage.toURL(analyticsOptions);
}
function updateByContainerWidth(steps?: number | number[], element?:HTMLImageElement, responsiveImage?: CloudinaryImage){
let responsiveImgWidth = element.parentElement.clientWidth;
if(isNum(steps)){
const WIDTH_INTERVALS = steps as number;
responsiveImgWidth = Math.ceil(responsiveImgWidth / WIDTH_INTERVALS ) * WIDTH_INTERVALS;
} else if(Array.isArray(steps)){
responsiveImgWidth = steps.reduce((prev, curr) =>{
return (Math.abs(curr - responsiveImgWidth) < Math.abs(prev - responsiveImgWidth) ? curr : prev);
});
}
responsiveImage.transformation.actions.forEach((action, index) => {
if (action instanceof Action && action.getActionTag() === 'responsive') {
responsiveImage.transformation.actions[index] = scale(responsiveImgWidth).setActionTag('responsive');
}
});
}