var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
define(["require", "exports", "interactjs", "@wedxml/common/browsers"], function (require, exports, interactjs_1, browsers) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    interactjs_1 = __importDefault(interactjs_1);
    browsers = __importStar(browsers);
    /**
     * This records changes in such a way that if any of the changes cannot take
     * effect, then all the changes are "rolled back". It is called pseudo-atomic
     * because it is not really meant to track any changes that do not happen
     * through instances of this class. This is needed because we are changing the
     * size of multiple elements, and beyond a certain "smallness", some elements
     * won't register any change in dimensions (perhaps due to "min-..." styles.
     */
    class PseudoAtomicRectChange {
        constructor() {
            this.changes = [];
            this.rolledback = false;
        }
        updateElementRect(el, dx, dy) {
            // If we've already rolled back, we don't do anything.
            if (this.rolledback) {
                return;
            }
            let rect = el.getBoundingClientRect();
            // This works around a fractional pixel issue in IE. We set the element to
            // the dimensions returned by getBoundingClientRect and then reacquire the
            // dimensions to account for any funny adjustments IE may decide to do.
            if (browsers.MSIE) {
                el.style.width = `${rect.width}px`;
                el.style.height = `${rect.height}px`;
                rect = el.getBoundingClientRect();
            }
            const width = rect.width + dx;
            const height = rect.height + dy;
            el.style.width = `${width}px`;
            el.style.height = `${height}px`;
            this.changes.push({ el: el, rect: rect });
            const newRect = el.getBoundingClientRect();
            // Check whether the change "took". If not, roll back.
            if (newRect.width !== width || newRect.height !== height) {
                this.rollback();
            }
        }
        rollback() {
            const changes = this.changes;
            for (const change of changes) {
                const el = change.el;
                const rect = change.rect;
                el.style.width = `${rect.width}px`;
                el.style.height = `${rect.height}px`;
            }
            this.rolledback = true;
        }
    }
    /**
     * Make a bootstrap dialog resizable by clicking on its edge.
     *
     * @param $top The top level element of the dialog.
     */
    function makeResizable($top) {
        // We listen to resizestart and resizeend to deal with the following scenario:
        // the user starts resizing the modal, it goes beyond the limits of how big it
        // can be resized, the mouse pointer moves outside the modal window and the
        // user releases the button when the pointer is outside. Without the use of
        // ignoreBackdropClick, this causes the modal to close.
        const content = $top.find(".modal-content")[0];
        const body = $top.find(".modal-body")[0];
        interactjs_1.default(content)
            .resizable({})
            .on("resizestart", () => {
            const modal = $top.data("bs.modal");
            if (modal == null) {
                return; // Deal with edge cases.
            }
            // Prevent modal closure.
            modal.ignoreBackdropClick = true;
        })
            .on("resizeend", () => {
            // We use a setTimeout otherwise we turn ignoreBackdropClick too soon.
            setTimeout(() => {
                const modal = $top.data("bs.modal");
                if (modal == null) {
                    return; // Deal with edge cases.
                }
                modal.ignoreBackdropClick = false;
            }, 0);
        })
            .on("resizemove", (event) => {
            const target = event.target;
            const change = new PseudoAtomicRectChange();
            change.updateElementRect(target, event.dx, event.dy);
            change.updateElementRect(body, event.dx, event.dy);
        });
    }
    exports.makeResizable = makeResizable;
    /**
     * Make a bootstrap dialog draggable by clicking and dragging the header.
     *
     * @param $top The top level element of the dialog.
     */
    function makeDraggable($top) {
        const win = $top[0].ownerDocument.defaultView;
        const header = $top.find(".modal-header")[0];
        const content = $top.find(".modal-content")[0];
        let startLeft;
        let startTop;
        interactjs_1.default(header)
            .draggable({
            restrict: {
                restriction: {
                    left: 0,
                    top: 0,
                    right: win.innerWidth - 10,
                    bottom: win.innerHeight - 10,
                },
            },
        })
            .on("dragstart", () => {
            startLeft = content.offsetLeft;
            startTop = content.offsetTop;
        })
            .on("dragmove", (event) => {
            content.style.left = `${startLeft + event.clientX - event.clientX0}px`;
            content.style.top = `${startTop + event.clientY - event.clientY0}px`;
        });
    }
    exports.makeDraggable = makeDraggable;
});
//# sourceMappingURL=interactivity.js.map