239 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import AbstractPopup from './abstractpopup.js'
 | 
						|
import Button from './button.js'
 | 
						|
import ButtonGroup from './buttongroup.js'
 | 
						|
 | 
						|
/**
 | 
						|
 * Class that represents a PixiJS InteractivePopup.
 | 
						|
 * The class is used for various other Popup-like classes
 | 
						|
 * like Popup, Message...
 | 
						|
 *
 | 
						|
 * @class
 | 
						|
 * @abstract
 | 
						|
 * @extends AbstractPopup
 | 
						|
 */
 | 
						|
export class InteractivePopup extends AbstractPopup {
 | 
						|
    /**
 | 
						|
     * Creates an instance of an InteractivePopup (only for internal use).
 | 
						|
     *
 | 
						|
     * @constructor
 | 
						|
     * @param {object} [opts] - An options object to specify to style and behaviour of the popup.
 | 
						|
     * @param {boolean} [opts.closeOnPopup=false] - Should the popup be closed when the user clicks on the popup?
 | 
						|
     * @param {boolean|string} [opts.closeButton=true] - Should a close button be displayed on the upper right corner? Alternatively, a URL to the image can be specified.
 | 
						|
     * @param {object} [opts.button] - A Button object to be display on the lower right corner.
 | 
						|
     * @param {object} [opts.buttonGroup] - A ButtonGroup object to be displayed on the lower right corner.
 | 
						|
     */
 | 
						|
    constructor(opts = {}) {
 | 
						|
        opts = Object.assign(
 | 
						|
            {},
 | 
						|
            {
 | 
						|
                closeOnPopup: false,
 | 
						|
                closeButton: true,
 | 
						|
                button: null,
 | 
						|
                buttonGroup: null,
 | 
						|
            },
 | 
						|
            opts
 | 
						|
        )
 | 
						|
 | 
						|
        super(opts)
 | 
						|
 | 
						|
        this._closeButton = null
 | 
						|
        this._buttons = null
 | 
						|
 | 
						|
        // padding
 | 
						|
        this.smallPadding = this.opts.padding / 2
 | 
						|
 | 
						|
        // setup
 | 
						|
        //-----------------
 | 
						|
        this.setup()
 | 
						|
 | 
						|
        // layout
 | 
						|
        //-----------------
 | 
						|
        this.layout()
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates the framework and instantiates everything.
 | 
						|
     *
 | 
						|
     * @private
 | 
						|
     * @return {AbstractPopup} A reference to the popup for chaining.
 | 
						|
     */
 | 
						|
    setup() {
 | 
						|
        super.setup()
 | 
						|
 | 
						|
        // interaction
 | 
						|
        //-----------------
 | 
						|
        this.on('pointerup', (e) => {
 | 
						|
            if (this.opts.closeOnPopup) {
 | 
						|
                this.hide()
 | 
						|
            } else {
 | 
						|
                e.stopPropagation()
 | 
						|
            }
 | 
						|
        })
 | 
						|
 | 
						|
        // closeButton
 | 
						|
        //-----------------
 | 
						|
        if (this.opts.closeButton) {
 | 
						|
            let url = null
 | 
						|
            if (typeof this.opts.closeButton === 'string' || this.opts.closeButton instanceof String) {
 | 
						|
                url = InteractivePopup.iconIsUrl(this.opts.closeButton)
 | 
						|
                    ? this.opts.closeButton
 | 
						|
                    : `../../assets/icons/${this.opts.closeButton}.png`
 | 
						|
            } else {
 | 
						|
                url = '../../assets/icons/close.png'
 | 
						|
            }
 | 
						|
 | 
						|
            let closeButton = PIXI.Sprite.from(url)
 | 
						|
            closeButton.width = this.headerStyle.fontSize
 | 
						|
            closeButton.height = closeButton.width
 | 
						|
            closeButton.tint = this.theme.color2
 | 
						|
            // This is needed, because the closeButton belongs to the content. The popup must resize with the closeButton.
 | 
						|
            if (this._header) {
 | 
						|
                closeButton.x = this._header.width + this.innerPadding
 | 
						|
            } else if (this._content) {
 | 
						|
                closeButton.x = this._content.width + this.innerPadding
 | 
						|
            }
 | 
						|
 | 
						|
            closeButton.interactive = true
 | 
						|
            closeButton.buttonMode = true
 | 
						|
            closeButton.on('pointerdown', (e) => {
 | 
						|
                this.hide()
 | 
						|
            })
 | 
						|
 | 
						|
            this._closeButton = closeButton
 | 
						|
            this.addChild(closeButton)
 | 
						|
 | 
						|
            // maxWidth is set and a closeButton should be displayed
 | 
						|
            //-----------------
 | 
						|
            if (this.opts.maxWidth) {
 | 
						|
                const wordWrapWidth =
 | 
						|
                    this.opts.maxWidth - 2 * this.opts.padding - this.smallPadding - this._closeButton.width
 | 
						|
                if (this._header) {
 | 
						|
                    this.headerStyle.wordWrapWidth = wordWrapWidth
 | 
						|
                } else if (this._content) {
 | 
						|
                    this.textStyle.wordWrapWidth = wordWrapWidth
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // buttons
 | 
						|
        //-----------------
 | 
						|
        if (this.opts.button || this.opts.buttonGroup) {
 | 
						|
            if (this.opts.button) {
 | 
						|
                this._buttons = new Button(Object.assign({ textStyle: this.theme.textStyleSmall }, this.opts.button))
 | 
						|
            } else {
 | 
						|
                this._buttons = new ButtonGroup(
 | 
						|
                    Object.assign({ textStyle: this.theme.textStyleSmall }, this.opts.buttonGroup)
 | 
						|
                )
 | 
						|
            }
 | 
						|
            this.addChild(this._buttons)
 | 
						|
 | 
						|
            this._buttons.y = this.innerPadding + this.sy
 | 
						|
        }
 | 
						|
 | 
						|
        return this
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Should be called to refresh the layout of the popup. Can be used after resizing.
 | 
						|
     *
 | 
						|
     * @return {AbstractPopup} A reference to the popup for chaining.
 | 
						|
     */
 | 
						|
    layout() {
 | 
						|
        super.layout()
 | 
						|
 | 
						|
        // closeButton
 | 
						|
        //-----------------
 | 
						|
        if (this.opts.closeButton) {
 | 
						|
            this._closeButton.x = this.wantedWidth - this.smallPadding - this._closeButton.width
 | 
						|
            this._closeButton.y = this.smallPadding
 | 
						|
        }
 | 
						|
 | 
						|
        // buttons
 | 
						|
        //-----------------
 | 
						|
        if (this._buttons) {
 | 
						|
            this._buttons.x = this.wantedWidth - this.opts.padding - this._buttons.width
 | 
						|
            this._buttons.y = this.wantedHeight - this.opts.padding - this._buttons.height
 | 
						|
        }
 | 
						|
 | 
						|
        return this
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Calculates the size of the children of the AbstractPopup.
 | 
						|
     * Cannot use getBounds() because it is not updated when children
 | 
						|
     * are removed.
 | 
						|
     *
 | 
						|
     * @private
 | 
						|
     * @override
 | 
						|
     * @returns {object} An JavaScript object width the keys width and height.
 | 
						|
     */
 | 
						|
    getInnerSize() {
 | 
						|
        let size = super.getInnerSize()
 | 
						|
 | 
						|
        if (this._closeButton) {
 | 
						|
            size.width += this.smallPadding + this._closeButton.width
 | 
						|
        }
 | 
						|
 | 
						|
        if (this._buttons) {
 | 
						|
            size.width = Math.max(size.width, this._buttons.x + this._buttons.width)
 | 
						|
            size.height += this.innerPadding + this._buttons.height
 | 
						|
        }
 | 
						|
 | 
						|
        return size
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Tests if an icon string is an url.
 | 
						|
     *
 | 
						|
     * @private
 | 
						|
     * @static
 | 
						|
     * @param {string} url - The url to test.
 | 
						|
     * @return {boolean} true if the url is an url to an image.
 | 
						|
     */
 | 
						|
    static iconIsUrl(url) {
 | 
						|
        return /\.(png|svg|gif|jpg|jpeg|tif|tiff)$/i.test(url)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Class that represents a PixiJS Popup.
 | 
						|
 *
 | 
						|
 * @example
 | 
						|
 * // Create the popup
 | 
						|
 * const popup = new Popup({
 | 
						|
 *     header: 'Goethe',
 | 
						|
 *     content: 'Man kann die Erfahrung nicht früh genug machen, wie entbehrlich man in der Welt ist.'
 | 
						|
 * })
 | 
						|
 *
 | 
						|
 * // Add the popup to a DisplayObject
 | 
						|
 * app.scene.addChild(popup)
 | 
						|
 *
 | 
						|
 * @class
 | 
						|
 * @extends InteractivePopup
 | 
						|
 * @see {@link https://www.iwm-tuebingen.de/iwmbrowser/lib/pixi/popup.html|DocTest}
 | 
						|
 */
 | 
						|
export default class Popup extends InteractivePopup {
 | 
						|
    /**
 | 
						|
     * Creates an instance of a Popup.
 | 
						|
     *
 | 
						|
     * @constructor
 | 
						|
     * @param {object} [opts] - An options object to specify to style and behaviour of the popup.
 | 
						|
     * @param {boolean|string} [opts.closeButton=false] - Should a close button be displayed on the upper right corner? Alternatively, a URL to the image can be specified.
 | 
						|
     * @param {number} [opts.minWidth=0] - The minimum width of the popup.
 | 
						|
     * @param {number} [opts.minHeight=0] - The minimum height of the popup.
 | 
						|
     */
 | 
						|
    constructor(opts = {}) {
 | 
						|
        opts = Object.assign(
 | 
						|
            {},
 | 
						|
            {
 | 
						|
                closeButton: false,
 | 
						|
                minWidth: 0,
 | 
						|
                minHeight: 0,
 | 
						|
            },
 | 
						|
            opts
 | 
						|
        )
 | 
						|
 | 
						|
        super(opts)
 | 
						|
    }
 | 
						|
}
 |