/**
 * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
/**
 * @module image/image/imageplaceholder
 */
import { Plugin } from 'ckeditor5/src/core.js';
import ImageUtils from '../imageutils.js';
import ImageLoadObserver from './imageloadobserver.js';
import '../../theme/imageplaceholder.css';
/**
 * Adds support for image placeholder that is automatically removed when the image is loaded.
 */
export default class ImagePlaceholder extends Plugin {
    /**
     * @inheritDoc
     */
    static get requires() {
        return [ImageUtils];
    }
    /**
     * @inheritDoc
     */
    static get pluginName() {
        return 'ImagePlaceholder';
    }
    /**
     * @inheritDoc
     */
    afterInit() {
        this._setupSchema();
        this._setupConversion();
        this._setupLoadListener();
    }
    /**
     * Extends model schema.
     */
    _setupSchema() {
        const schema = this.editor.model.schema;
        // Wait for ImageBlockEditing or ImageInlineEditing to register their elements first,
        // that's why doing this in afterInit() instead of init().
        if (schema.isRegistered('imageBlock')) {
            schema.extend('imageBlock', {
                allowAttributes: ['placeholder']
            });
        }
        if (schema.isRegistered('imageInline')) {
            schema.extend('imageInline', {
                allowAttributes: ['placeholder']
            });
        }
    }
    /**
     * Registers converters.
     */
    _setupConversion() {
        const editor = this.editor;
        const conversion = editor.conversion;
        const imageUtils = editor.plugins.get('ImageUtils');
        conversion.for('editingDowncast').add(dispatcher => {
            dispatcher.on('attribute:placeholder', (evt, data, conversionApi) => {
                if (!conversionApi.consumable.test(data.item, evt.name)) {
                    return;
                }
                if (!data.item.is('element', 'imageBlock') && !data.item.is('element', 'imageInline')) {
                    return;
                }
                conversionApi.consumable.consume(data.item, evt.name);
                const viewWriter = conversionApi.writer;
                const element = conversionApi.mapper.toViewElement(data.item);
                const img = imageUtils.findViewImgElement(element);
                if (data.attributeNewValue) {
                    viewWriter.addClass('image_placeholder', img);
                    viewWriter.setStyle('background-image', `url(${data.attributeNewValue})`, img);
                    viewWriter.setCustomProperty('editingPipeline:doNotReuseOnce', true, img);
                }
                else {
                    viewWriter.removeClass('image_placeholder', img);
                    viewWriter.removeStyle('background-image', img);
                }
            });
        });
    }
    /**
     * Prepares listener for image load.
     */
    _setupLoadListener() {
        const editor = this.editor;
        const model = editor.model;
        const editing = editor.editing;
        const editingView = editing.view;
        const imageUtils = editor.plugins.get('ImageUtils');
        editingView.addObserver(ImageLoadObserver);
        this.listenTo(editingView.document, 'imageLoaded', (evt, domEvent) => {
            const imgViewElement = editingView.domConverter.mapDomToView(domEvent.target);
            if (!imgViewElement) {
                return;
            }
            const viewElement = imageUtils.getImageWidgetFromImageView(imgViewElement);
            if (!viewElement) {
                return;
            }
            const modelElement = editing.mapper.toModelElement(viewElement);
            if (!modelElement || !modelElement.hasAttribute('placeholder')) {
                return;
            }
            model.enqueueChange({ isUndoable: false }, writer => {
                writer.removeAttribute('placeholder', modelElement);
            });
        });
    }
}
