Source: pixi/modal.js

pixi/modal.js

import Theme from './theme.js'
import { InteractivePopup } from './popup.js'

/**
 * Class that represents a PixiJS Modal.
 *
 * @example
 * // Create the button and the modal when clicked
 * const button = new Button({
 *     label: 'Show Modal',
 *     action: e => {
 *         const modal = new Modal({
 *             app: app,
 *             header: 'This is the header',
 *             content: 'This is the text.'
 *         })
 *         app.scene.addChild(modal)
 *     }
 * })
 *
 * // Add the button to a DisplayObject
 * app.scene.addChild(button)
 *
 * @class
 * @extends PIXI.Container
 * @extends InteractivePopup
 * @see {@link http://pixijs.download/dev/docs/PIXI.Container.html|PIXI.Container}
 * @see {@link https://www.iwm-tuebingen.de/iwmbrowser/lib/pixi/modal.html|DocTest}
 */
export default class Modal extends PIXI.Container {
    /**
     * Creates an instance of a Modal.
     *
     * @constructor
     * @param {object} [opts] - An options object to specify to style and behaviour of the modal.
     * @param {number} [opts.id=auto generated] - The id of the modal.
     * @param {PIXIApp} [opts.app=window.app] - The app where the modal belongs to.
     * @param {number} [opts.backgroundFill=Theme.background] - The color of the background.
     * @param {number} [opts.backgroundFillAlpha=0.6] - The opacity of the background.
     * @param {boolean} [opts.closeOnBackground=true] - Should the modal be closed when the user clicks the
     *     background?
     * @param {boolean} [opts.visible=true] - Is the modal initially visible (property visible)?
     */
    constructor(opts = {}) {
        super()

        const theme = Theme.fromString(opts.theme)
        this.theme = theme

        this.opts = Object.assign(
            {},
            {
                id: PIXI.utils.uid(),
                app: window.app,
                backgroundFill: theme.background,
                backgroundFillAlpha: 0.6,
                closeOnBackground: true,
                visible: true
            },
            opts
        )

        this.id = this.opts.id

        this.background = null
        this.popup = null

        this.alpha = 0
        this.visible = this.opts.visible

        // setup
        //-----------------
        this.setup()

        // layout
        //-----------------
        this.layout()
    }

    /**
     * Creates children and instantiates everything.
     *
     * @private
     * @return {Modal} A reference to the modal for chaining.
     */
    setup() {
        // interaction
        //-----------------
        this.interactive = true
        this.on('added', e => {
            if (this.visible) {
                this.show()
            }
        })

        // background
        //-----------------
        let background = new PIXI.Graphics()
        this.background = background
        this.addChild(this.background)

        if (this.opts.closeOnBackground) {
            background.interactive = true
            background.on('pointerup', e => {
                this.hide()
            })
        }

        // popup
        //-----------------
        const popupOpts = Object.assign({}, this.opts, {
            visible: true,
            onHidden: () => {
                this.hide()
            }
        })
        let popup = new InteractivePopup(popupOpts)
        this.popup = popup
        this.addChild(popup)
        popup.show()

        return this
    }

    /**
     * Should be called to refresh the layout of the modal. Can be used after resizing.
     *
     * @return {Modal} A reference to the modal for chaining.
     */
    layout() {
        const width = this.opts.app.size.width
        const height = this.opts.app.size.height

        // background
        //-----------------
        this.background.clear()
        this.background.beginFill(this.opts.backgroundFill, this.opts.backgroundFillAlpha)
        this.background.drawRect(0, 0, width, height)
        this.background.endFill()

        // position
        this.popup.x = width / 2 - this.popup.width / 2
        this.popup.y = height / 2 - this.popup.height / 2

        return this
    }

    /**
     * Shows the modal (sets his alpha values to 1).
     *
     * @return {Modal} A reference to the modal for chaining.
     */
    show() {
        TweenLite.to(this, this.theme.fast, {
            alpha: 1,
            onStart: () => (this.visible = true)
        })

        return this
    }

    /**
     * Hides the modal (sets his alpha values to 0).
     *
     * @return {Modal} A reference to the modal for chaining.
     */
    hide() {
        TweenLite.to(this, this.theme.fast, {
            alpha: 0,
            onComplete: () => (this.visible = false)
        })

        return this
    }

    /**
     * Sets or gets the header. The getter always returns a PIXI.Text object. The setter can receive
     * a string or a PIXI.Text object.
     *
     * @member {string|PIXI.Text}
     */
    get header() {
        return this.popup.header
    }
    set header(value) {
        this.opts.header = value
        this.background.destroy()
        this.popup.destroy()
        this.setup().layout()
    }

    /**
     * Sets or gets the content. The getter always returns an PIXI.DisplayObject. The setter can receive
     * a string or a PIXI.DisplayObject.
     *
     * @member {string|PIXI.DisplayObject}
     */
    get content() {
        return this.popup.content
    }
    set content(value) {
        this.opts.content = value
        this.background.destroy()
        this.popup.destroy()
        this.setup().layout()
    }
}