Source: popup.js

/*************************************************************
 *
 *  Copyright (c) 2015-2016 The MathJax Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
/**
 * @fileoverview Class of popup windows. Each object can actually spawn multiple
 *      windows.
 *
 * @author v.sorge@mathjax.org (Volker Sorge)
 */
/// <reference path="context_menu.ts" />
/// <reference path="menu_util.ts" />
var ContextMenu;
(function (ContextMenu) {
    class Popup extends ContextMenu.AbstractPostable {
        /**
         * @constructor
         * @extends {AbstractPostable}
         * @param {string} title The title of the popup window.
         * @param {Function} content Function generating the content.
         */
        constructor(title, content) {
            super();
            this.title = '';
            /**
             * The last opened window.
             * @type {Window}
             */
            this.window = null;
            /**
             * The list of all windows opened by this object.
             * @type {Array.<Window>}
             */
            this.windowList = [];
            this.mobileFlag = false;
            this.active = null;
            this.title = title;
            this.content = content || function () { return ''; };
        }
        /**
         * Attaches the widget to a context menu.
         * @param {ContextMenu} menu The parent menu.
         */
        attachMenu(menu) {
            this.menu = menu;
        }
        /**
         * @override
         */
        post() {
            this.display();
        }
        /**
         * @override
         */
        display() {
            this.active = this.menu.getStore().getActive();
            let settings = [];
            for (let setting in Popup.popupSettings) {
                settings.push(setting + '=' + Popup.popupSettings[setting]);
            }
            this.window = window.open('', '_blank', settings.join(','));
            this.windowList.push(this.window);
            let doc = this.window.document;
            if (this.mobileFlag) {
                doc.open();
                doc.write('<html><head><meta name="viewport" ' +
                    'content="width=device-width, initial-scale=1.0" /><title>' +
                    this.title +
                    '</title></head><body style="font-size:85%">');
                doc.write('<pre>' + this.generateContent() + '</pre>');
                doc.write('<hr><input type="button" value="' +
                    //// TODO: Localise
                    'Close' + '" onclick="window.close()" />');
                doc.write('</body></html>');
                doc.close();
            }
            else {
                doc.open();
                doc.write('<html><head><title>' + this.title +
                    '</title></head><body style="font-size:85%">');
                doc.write('<table><tr><td><pre>' + this.generateContent() +
                    '</pre></td></tr></table>');
                doc.write('</body></html>');
                doc.close();
                setTimeout(this.resize.bind(this), 50);
            }
        }
        /**
         * @override
         */
        unpost() {
            this.windowList.forEach(x => x.close());
            this.window = null;
        }
        /**
         * Generates the content of the window.
         * @return {string} The generated content.
         */
        generateContent() {
            return this.content(this.active);
        }
        /**
         * Resizes the window so it fits snuggly around the content.
         * @private
         */
        resize() {
            let table = this.window.document.body.firstChild;
            let H = (this.window.outerHeight - this.window.innerHeight) || 30;
            let W = (this.window.outerWidth - this.window.innerWidth) || 30;
            W = Math.max(140, Math.min(Math.floor(.5 * screen.width), table.offsetWidth + W + 25));
            H = Math.max(40, Math.min(Math.floor(.5 * screen.height), table.offsetHeight + H + 25));
            this.window.resizeTo(W, H);
            let bb = this.active.getBoundingClientRect();
            if (bb) {
                let x = Math.max(0, Math.min(bb.right - Math.floor(W / 2), screen.width - W - 20));
                let y = Math.max(0, Math.min(bb.bottom - Math.floor(H / 2), screen.height - H - 20));
                this.window.moveTo(x, y);
            }
            this.active = null;
        }
    }
    Popup.popupSettings = {
        status: 'no',
        toolbar: 'no',
        locationbar: 'no',
        menubar: 'no',
        directories: 'no',
        personalbar: 'no',
        resizable: 'yes',
        scrollbars: 'yes',
        width: 400,
        height: 300,
        left: Math.round((screen.width - 400) / 2),
        top: Math.round((screen.height - 300) / 3)
    };
    ContextMenu.Popup = Popup;
})(ContextMenu || (ContextMenu = {}));