/*!
 * Pintura Image Editor 8.13.1
 * (c) 2018-2021 PQINA Inc. - All Rights Reserved
 * License: https://pqina.nl/pintura/license/
 */
/* eslint-disable */

var isFile = (v) => v instanceof File;

var isImage = (file) => /^image/.test(file.type);

var isString = (v) => typeof v === 'string';

let isSafari = null;
var isSafari$1 = () => {
    if (isSafari === null)
        isSafari = isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
    return isSafari;
};

var getImageElementSize = (imageElement) => new Promise((resolve, reject) => {
    let shouldAutoRemove = false;
    // test if image is attached to DOM, if not attached, attach so measurement is correct on Safari
    if (!imageElement.parentNode && isSafari$1()) {
        shouldAutoRemove = true;
        // has width 0 and height 0 to prevent rendering very big SVGs (without width and height) that will for one frame overflow the window and show a scrollbar
        imageElement.style.cssText = `position:absolute;visibility:hidden;pointer-events:none;left:0;top:0;width:0;height:0;`;
        document.body.appendChild(imageElement);
    }
    // start testing size
    const measure = () => {
        const width = imageElement.naturalWidth;
        const height = imageElement.naturalHeight;
        const hasSize = width && height;
        if (!hasSize)
            return;
        // clean up image if was attached for measuring
        if (shouldAutoRemove)
            imageElement.parentNode.removeChild(imageElement);
        clearInterval(intervalId);
        resolve({ width, height });
    };
    imageElement.onerror = (err) => {
        clearInterval(intervalId);
        reject(err);
    };
    const intervalId = setInterval(measure, 1);
    measure();
});

var getImageSize = async (image) => {
    // the image element we'll use to load the image
    let imageElement = image;
    // if is not an image element, it must be a valid image source
    if (!imageElement.src) {
        imageElement = new Image();
        imageElement.src = isString(image) ? image : URL.createObjectURL(image);
    }
    let size;
    try {
        size = await getImageElementSize(imageElement);
    }
    finally {
        isFile(image) && URL.revokeObjectURL(imageElement.src);
    }
    return size;
};

var isBlob = (v) => v instanceof Blob && !(v instanceof File);

var noop = (...args) => { };

let result$3 = null;
var isBrowser = () => {
    if (result$3 === null)
        result$3 = typeof window !== 'undefined' && typeof window.document !== 'undefined';
    return result$3;
};

var h = (name, attributes, children = []) => {
    const el = document.createElement(name);
    // @ts-ignore
    const descriptors = Object.getOwnPropertyDescriptors(el.__proto__);
    for (const key in attributes) {
        if (key === 'style') {
            el.style.cssText = attributes[key];
        }
        else if ((descriptors[key] && descriptors[key].set) ||
            /textContent|innerHTML/.test(key) ||
            typeof attributes[key] === 'function') {
            el[key] = attributes[key];
        }
        else {
            el.setAttribute(key, attributes[key]);
        }
    }
    children.forEach((child) => el.appendChild(child));
    return el;
};

var releaseCanvas = (canvas) => {
    canvas.width = 1;
    canvas.height = 1;
    const ctx = canvas.getContext('2d');
    ctx && ctx.clearRect(0, 0, 1, 1);
};

let result$2 = null;
var supportsWebGL2 = () => {
    if (result$2 === null) {
        if ('WebGL2RenderingContext' in window) {
            let canvas;
            try {
                canvas = h('canvas');
                result$2 = !!canvas.getContext('webgl2');
            }
            catch (err) {
                result$2 = false;
            }
            canvas && releaseCanvas(canvas);
        }
        else {
            result$2 = false;
        }
    }
    return result$2;
};

var getWebGLContext = (canvas, attrs) => {
    if (supportsWebGL2())
        return canvas.getContext('webgl2', attrs);
    return (canvas.getContext('webgl', attrs) ||
        canvas.getContext('experimental-webgl', attrs));
};

let result$1 = null;
var supportsWebGL = () => {
    if (result$1 === null) {
        const canvas = h('canvas');
        result$1 = !!getWebGLContext(canvas);
        releaseCanvas(canvas);
    }
    return result$1;
};

const isOperaMini = () => Object.prototype.toString.call(window['operamini']) === '[object OperaMini]';
const hasPromises = () => 'Promise' in window;
const hasCreateObjectURL = () => 'URL' in window && 'createObjectURL' in window.URL;
const hasVisibility = () => 'visibilityState' in document;
const hasTiming = () => 'performance' in window; // iOS 8.x
const hasFileConstructor = () => 'File' in window; // excludes IE11
let result = null;
var isModernBrowser = () => {
    if (result === null)
        result =
            isBrowser() &&
                // Can't run on Opera Mini due to lack of everything
                !isOperaMini() &&
                // Require these APIs to feature detect a modern browser
                hasVisibility() &&
                hasPromises() &&
                hasFileConstructor() &&
                hasCreateObjectURL() &&
                hasTiming();
    return result;
};

/**
 * Image Edit Proxy Plugin
 */
const plugin = (_) => {
    const { addFilter, utils, views } = _;
    const { Type, createRoute } = utils;
    const { fileActionButton } = views;
    const getEditorSafe = (editor) => (editor === null ? {} : editor);
    addFilter('SHOULD_REMOVE_ON_REVERT', (shouldRemove, { item, query }) => new Promise((resolve) => {
        const { file } = item;
        // if this file is editable it shouldn't be removed immidiately even when instant uploading
        const canEdit = query('GET_ALLOW_IMAGE_EDITOR') &&
            query('GET_IMAGE_EDITOR_ALLOW_EDIT') &&
            query('GET_IMAGE_EDITOR_SUPPORT_EDIT') &&
            query('GET_IMAGE_EDITOR_SUPPORT_IMAGE')(file);
        // if the file cannot be edited it should be removed on revert
        resolve(!canEdit);
    }));
    // open editor when loading a new item
    addFilter('DID_LOAD_ITEM', (item, { query, dispatch }) => new Promise((resolve, reject) => {
        // if is temp or local file
        if (item.origin > 1) {
            resolve(item);
            return;
        }
        // get file reference
        const { file } = item;
        if (!query('GET_ALLOW_IMAGE_EDITOR') ||
            !query('GET_IMAGE_EDITOR_INSTANT_EDIT' ))
            return resolve(item);
        // exit if this is not an image
        if (!query('GET_IMAGE_EDITOR_SUPPORT_IMAGE')(file))
            return resolve(item);
        // request editing of a file
        const requestEdit = () => {
            if (!editRequestQueue.length)
                return;
            const { item, resolve, reject } = editRequestQueue[0];
            dispatch('EDIT_ITEM', {
                id: item.id,
                handleEditorResponse: createEditorResponseHandler(item, resolve, reject),
            });
        };
        // is called when the user confirms editing the file
        const createEditorResponseHandler = (item, resolve, reject) => (userDidConfirm) => {
            // remove item
            editRequestQueue.shift();
            // handle item
            if (userDidConfirm) {
                resolve(item);
            }
            else {
                reject(item);
            }
            // TODO: Fix, should not be needed to kick the internal loop in case no processes are running
            dispatch('KICK');
            // handle next item!
            requestEdit();
        };
        queueEditRequest({ item, resolve, reject });
        if (editRequestQueue.length === 1) {
            requestEdit();
        }
    }));
    // extend item methods
    addFilter('DID_CREATE_ITEM', (item, { query, dispatch }) => {
        item.extend('edit', () => {
            dispatch('EDIT_ITEM', { id: item.id });
        });
    });
    const editRequestQueue = [];
    const queueEditRequest = (editRequest) => {
        editRequestQueue.push(editRequest);
        return editRequest;
    };
    const couldTransformFile = (query) => {
        // no editor defined, then exit
        const { imageProcessor, imageReader, imageWriter } = getEditorSafe(query('GET_IMAGE_EDITOR'));
        return (query('GET_IMAGE_EDITOR_WRITE_IMAGE') &&
            query('GET_IMAGE_EDITOR_SUPPORT_WRITE_IMAGE') &&
            imageProcessor &&
            imageReader &&
            imageWriter);
    };
    // called for each view that is created right after the 'create' method
    addFilter('CREATE_VIEW', (viewAPI) => {
        // get reference to created view
        const { is, view, query } = viewAPI;
        if (!query('GET_ALLOW_IMAGE_EDITOR'))
            return;
        if (!query('GET_IMAGE_EDITOR_SUPPORT_WRITE_IMAGE'))
            return;
        const supportsFilePoster = query('GET_ALLOW_FILE_POSTER');
        // only run for either the file or the file info panel
        const shouldExtendView = (is('file-info') && !supportsFilePoster) || (is('file') && supportsFilePoster);
        if (!shouldExtendView)
            return;
        // no editor defined, then exit
        const { createEditor, imageProcessor, imageReader, imageWriter, editorOptions, legacyDataToImageState, imageState: imageBaseState, } = getEditorSafe(query('GET_IMAGE_EDITOR'));
        if (!imageReader || !imageWriter || !editorOptions || !editorOptions.locale)
            return;
        // remove default image reader and writer if set
        delete editorOptions.imageReader;
        delete editorOptions.imageWriter;
        const [createImageReader, imageReaderOptions] = imageReader;
        const [createImageWriter = noop, imageWriterOptions] = imageWriter;
        // tests if file item has poster
        const getItemByProps = (props) => {
            const { id } = props;
            const item = query('GET_ITEM', id);
            return item;
        };
        const hasPoster = (root, props) => {
            if (!query('GET_ALLOW_FILE_POSTER'))
                return false;
            const item = getItemByProps(props);
            if (!item)
                return;
            // test if is filtered
            if (!query('GET_FILE_POSTER_FILTER_ITEM')(item))
                return false;
            const poster = item.getMetadata('poster');
            return !!poster;
        };
        // generate preview
        const getPosterTargetSize = (root, targetSize) => {
            const posterHeight = root.query('GET_FILE_POSTER_HEIGHT');
            const maxPosterHeight = root.query('GET_FILE_POSTER_MAX_HEIGHT');
            if (posterHeight) {
                targetSize.width = posterHeight * 2;
                targetSize.height = posterHeight * 2;
            }
            else if (maxPosterHeight) {
                targetSize.width = maxPosterHeight * 2;
                targetSize.height = maxPosterHeight * 2;
            }
            return targetSize;
        };
        const createEditorOptions = (root) => {
            const targetSize = getPosterTargetSize(root, {
                width: 512,
                height: 512,
            });
            return {
                ...editorOptions,
                imageReader: createImageReader(imageReaderOptions),
                imageWriter: createImageWriter({
                    // poster size
                    targetSize,
                    // can optionally overwrite poster size
                    ...(imageWriterOptions || {}),
                }),
            };
        };
        const createImagePoster = ({ root, props }) => {
            // need image processor to create image poster
            if (!imageProcessor)
                return;
            const item = getItemByProps(props);
            if (!item)
                return;
            const file = item.file;
            const imageState = item.getMetadata('imageState');
            const options = {
                ...createEditorOptions(root),
                imageState: {
                    ...imageBaseState,
                    ...imageState,
                },
            };
            imageProcessor(file, options).then(({ dest }) => {
                item.setMetadata('poster', URL.createObjectURL(dest), true);
            });
        };
        // opens the editor, if it does not already exist, it creates the editor
        const openImageEditor = ({ root, props, action }) => {
            const { handleEditorResponse } = action;
            // get item
            const item = getItemByProps(props);
            // file to open
            const file = item.file;
            // open the editor (sets editor properties and imageState property)
            const editor = createEditor({
                ...createEditorOptions(root),
                src: file,
            });
            // when the image has loaded, update the editor
            editor.on('load', ({ size }) => {
                // get current image edit state
                let imageState = item.getMetadata('imageState');
                imageState = legacyDataToImageState
                    ? legacyDataToImageState(editor, size, imageState)
                    : imageState;
                // update editor view based on image edit state
                editor.imageState = {
                    ...imageBaseState,
                    ...imageState,
                };
            });
            editor.on('process', ({ imageState, dest }) => {
                // if already has post URL, try to revoke
                const poster = item.getMetadata('poster');
                poster && URL.revokeObjectURL(item.getMetadata('poster'));
                // store state, two seperate actions because we want to trigger preparefile when setting `imageState`
                item.setMetadata('poster', URL.createObjectURL(dest));
                item.setMetadata('imageState', imageState);
                // used in instant edit mode
                if (!handleEditorResponse)
                    return;
                handleEditorResponse(true);
            });
            editor.on('close', () => {
                // used in instant edit mode
                if (!handleEditorResponse)
                    return;
                handleEditorResponse(false);
            });
        };
        //#region view
        const didLoadItem = ({ root, props }) => {
            const { id } = props;
            // try to access item
            const item = query('GET_ITEM', id);
            if (!item)
                return;
            // get the file object
            const file = item.file;
            // exit if this is not an image
            if (!query('GET_IMAGE_EDITOR_SUPPORT_IMAGE')(file))
                return;
            if (query('GET_ALLOW_FILE_POSTER') && !item.getMetadata('poster')) {
                root.dispatch('REQUEST_CREATE_IMAGE_POSTER', { id });
            }
            if (!query('GET_IMAGE_EDITOR_ALLOW_EDIT') || !query('GET_IMAGE_EDITOR_SUPPORT_EDIT'))
                return;
            // handle interactions
            root.ref.handleEdit = (e) => {
                e.stopPropagation();
                root.dispatch('EDIT_ITEM', { id });
            };
            updateEditButton(root, props);
        };
        const updateEditButton = (root, props) => {
            root.ref.buttonEditItem && root.removeChildView(root.ref.buttonEditItem);
            if (root.ref.editButton && root.ref.editButton.parentNode) {
                root.ref.editButton.parentNode.removeChild(root.ref.editButton);
            }
            if (hasPoster(root, props)) {
                // add edit button to preview
                const buttonView = view.createChildView(fileActionButton, {
                    label: 'edit',
                    icon: query('GET_IMAGE_EDITOR_ICON_EDIT'),
                    opacity: 0,
                });
                // edit item classname
                buttonView.element.classList.add('filepond--action-edit-item');
                buttonView.element.dataset.align = query('GET_STYLE_IMAGE_EDITOR_BUTTON_EDIT_ITEM_POSITION');
                buttonView.on('click', root.ref.handleEdit);
                root.ref.buttonEditItem = view.appendChildView(buttonView);
            }
            else {
                // view is file info
                const filenameElement = view.element.querySelector('.filepond--file-info-main');
                const editButton = document.createElement('button');
                editButton.className = 'filepond--action-edit-item-alt';
                editButton.innerHTML = query('GET_IMAGE_EDITOR_ICON_EDIT') + '<span>edit</span>';
                editButton.addEventListener('click', root.ref.handleEdit);
                filenameElement.appendChild(editButton);
                root.ref.editButton = editButton;
            }
        };
        const didUpdateItemMetadata = ({ root, props, action }) => {
            if (!/poster/.test(action.change.key))
                return;
            if (!query('GET_IMAGE_EDITOR_ALLOW_EDIT') || !query('GET_IMAGE_EDITOR_SUPPORT_EDIT'))
                return;
            updateEditButton(root, props);
        };
        view.registerDestroyer(({ root }) => {
            if (root.ref.buttonEditItem) {
                root.ref.buttonEditItem.off('click', root.ref.handleEdit);
            }
            if (root.ref.editButton) {
                root.ref.editButton.removeEventListener('click', root.ref.handleEdit);
            }
        });
        const routes = {
            EDIT_ITEM: openImageEditor,
            DID_LOAD_ITEM: didLoadItem,
            DID_UPDATE_ITEM_METADATA: didUpdateItemMetadata,
            DID_REMOVE_ITEM: ({ props }) => {
                const { id } = props;
                const item = query('GET_ITEM', id);
                if (!item)
                    return;
                const poster = item.getMetadata('poster');
                poster && URL.revokeObjectURL(poster);
            },
            REQUEST_CREATE_IMAGE_POSTER: createImagePoster,
            DID_FILE_POSTER_LOAD: undefined,
        };
        if (supportsFilePoster) {
            // view is file
            const didPosterUpdate = ({ root }) => {
                if (!root.ref.buttonEditItem)
                    return;
                root.ref.buttonEditItem.opacity = 1;
            };
            routes.DID_FILE_POSTER_LOAD = didPosterUpdate;
        }
        //#endregion
        // start writing
        view.registerWriter(createRoute(routes));
    });
    //#region write image
    addFilter('SHOULD_PREPARE_OUTPUT', (shouldPrepareOutput, { query, change, item }) => new Promise((resolve) => {
        if (!query('GET_IMAGE_EDITOR_SUPPORT_IMAGE')(item.file))
            return resolve(false);
        if (change && !/imageState/.test(change.key))
            return resolve(false);
        resolve(!query('IS_ASYNC'));
    }));
    const shouldTransformFile = (query, file, item) => new Promise((resolve) => {
        // invalid item
        if (!couldTransformFile(query) ||
            item.archived ||
            (!isFile(file) && !isBlob(file)) ||
            !query('GET_IMAGE_EDITOR_SUPPORT_IMAGE')(file)) {
            return resolve(false);
        }
        // if size can't be read this browser doesn't support image
        getImageSize(file)
            .then(() => {
            const fn = query('GET_IMAGE_TRANSFORM_IMAGE_FILTER');
            if (fn) {
                const filterResult = fn(file);
                if (typeof filterResult === 'boolean') {
                    return resolve(filterResult);
                }
                if (typeof filterResult.then === 'function') {
                    return filterResult.then(resolve);
                }
            }
            resolve(true);
        })
            .catch(() => {
            resolve(false);
        });
    });
    // subscribe to file transformations
    addFilter('PREPARE_OUTPUT', (file, { query, item }) => {
        const writeOutputImage = (file) => new Promise((resolve, reject) => {
            const imageState = item.getMetadata('imageState');
            // no editor defined, then exit
            const { imageProcessor, imageReader, imageWriter, editorOptions, imageState: imageBaseState, } = getEditorSafe(query('GET_IMAGE_EDITOR'));
            if (!imageProcessor || !imageReader || !imageWriter || !editorOptions)
                return;
            const [createImageReader, imageReaderOptions] = imageReader;
            const [createImageWriter = noop, imageWriterOptions] = imageWriter;
            imageProcessor(file, {
                ...editorOptions,
                imageReader: createImageReader(imageReaderOptions),
                imageWriter: createImageWriter(imageWriterOptions),
                imageState: {
                    ...imageBaseState,
                    ...imageState,
                },
            })
                .then(resolve)
                .catch(reject);
        });
        return new Promise((resolve) => {
            shouldTransformFile(query, file, item).then((shouldWrite) => {
                if (!shouldWrite)
                    return resolve(file);
                writeOutputImage(file).then((res) => {
                    const afterFn = query('GET_IMAGE_EDITOR_AFTER_WRITE_IMAGE');
                    if (afterFn)
                        return afterFn(res).then(resolve);
                    // @ts-ignore
                    resolve(res.dest);
                });
            });
        });
    });
    //#endregion
    // Expose plugin options
    return {
        options: {
            // enable or disable image editing
            allowImageEditor: [true, Type.BOOLEAN],
            // open editor when image is dropped
            imageEditorInstantEdit: [false, Type.BOOLEAN],
            // allow editing
            imageEditorAllowEdit: [true, Type.BOOLEAN],
            // cannot edit if no WebGL or is <=IE11
            imageEditorSupportEdit: [
                isBrowser() && isModernBrowser() && supportsWebGL(),
                Type.BOOLEAN,
            ],
            // receives file and should return true if can edit
            imageEditorSupportImage: [isImage, Type.FUNCTION],
            // cannot write if is <= IE11
            imageEditorSupportWriteImage: [isModernBrowser(), Type.BOOLEAN],
            // should output image
            imageEditorWriteImage: [true, Type.BOOLEAN],
            // receives written image and can return single or more images
            imageEditorAfterWriteImage: [undefined, Type.FUNCTION],
            // editor object
            imageEditor: [null, Type.OBJECT],
            // the icon to use for the edit button
            imageEditorIconEdit: [
                '<svg width="26" height="26" viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M8.5 17h1.586l7-7L15.5 8.414l-7 7V17zm-1.707-2.707l8-8a1 1 0 0 1 1.414 0l3 3a1 1 0 0 1 0 1.414l-8 8A1 1 0 0 1 10.5 19h-3a1 1 0 0 1-1-1v-3a1 1 0 0 1 .293-.707z" fill="currentColor" fill-rule="nonzero"/></svg>',
                Type.STRING,
            ],
            // location of processing button
            styleImageEditorButtonEditItemPosition: ['bottom center', Type.STRING],
        },
    };
};
// fire pluginloaded event if running in browser, this allows registering the plugin when using async script tags
if (isBrowser())
    document.dispatchEvent(new CustomEvent('FilePond:pluginloaded', { detail: plugin }));

export default plugin;
