Source: abstract_menu.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 Abstract class of context menus.
 *
 * @author volker.sorge@gmail.com (Volker Sorge)
 */
/// <reference path="abstract_postable.ts" />
/// <reference path="menu.ts" />
/// <reference path="menu_element.ts" />
/// <reference path="item.ts" />
/// <reference path="variable_pool.ts" />
var ContextMenu;
(function (ContextMenu) {
    class AbstractMenu extends ContextMenu.AbstractPostable {
        /**
         * @constructor
         * @extends {AbstractPostable}
         * @implements {Menu}
         */
        constructor(...args) {
            super(...args);
            /**
             * @override
             */
            this.className = ContextMenu.HtmlClasses['CONTEXTMENU'];
            /**
             * @override
             */
            this.role = 'menu';
            this.items = [];
        }
        /**
         * @override
         */
        getItems() {
            return this.items;
        }
        ;
        /**
         * @override
         */
        getPool() {
            return this.variablePool;
        }
        ;
        /**
         * @override
         */
        getFocused() {
            return this.focused;
        }
        /**
         * @override
         */
        setFocused(item) {
            if (this.focused === item) {
                return;
            }
            if (!this.focused) {
                this.unfocus();
            }
            // Order here is important for test in submenu.unfocus.
            let old = this.focused;
            this.focused = item;
            if (old) {
                old.unfocus();
            }
        }
        /**
         * @override
         */
        up(event) {
            let items = this.getItems().filter(x => (x instanceof ContextMenu.AbstractItem) && (!x.isHidden()));
            if (items.length === 0) {
                return;
            }
            if (!this.focused) {
                items[items.length - 1].focus();
                return;
            }
            let index = items.indexOf(this.focused);
            if (index === -1) {
                return;
            }
            index = index ? --index : items.length - 1;
            items[index].focus();
        }
        /**
         * @override
         */
        down(event) {
            let items = this.getItems().filter(x => (x instanceof ContextMenu.AbstractItem) && (!x.isHidden()));
            if (items.length === 0) {
                return;
            }
            if (!this.focused) {
                items[0].focus();
                return;
            }
            let index = items.indexOf(this.focused);
            if (index === -1) {
                return;
            }
            index++;
            index = (index === items.length) ? 0 : index;
            items[index].focus();
        }
        /**
         * @override
         */
        generateHtml() {
            super.generateHtml();
            this.generateMenu();
        }
        /**
         * @override
         */
        generateMenu() {
            let html = this.getHtml();
            html.classList.add(ContextMenu.HtmlClasses['MENU']);
            for (let i = 0, item; item = this.items[i]; i++) {
                if (!item.isHidden()) {
                    html.appendChild(item.getHtml());
                    continue;
                }
                let itemHtml = item.getHtml();
                if (itemHtml.parentNode) {
                    itemHtml.parentNode.removeChild(itemHtml);
                }
            }
        }
        /**
         * @override
         */
        unpostSubmenus() {
            let submenus = this.items.filter(x => x instanceof ContextMenu.Submenu);
            for (let i = 0, submenu; submenu = submenus[i]; i++) {
                submenu.getSubmenu().unpost();
                if (submenu !== this.getFocused()) {
                    submenu.unfocus();
                }
            }
        }
        /**
         * @override
         */
        unpost() {
            super.unpost();
            this.unpostSubmenus();
            this.setFocused(null);
        }
        /**
         * @override
         */
        find(id) {
            for (let item of this.getItems()) {
                if (item.getType() === 'rule') {
                    continue;
                }
                if (item.getId() === id) {
                    return item;
                }
                if (item.getType() === 'submenu') {
                    let result = item.getSubmenu().find(id);
                    if (result) {
                        return result;
                    }
                }
            }
            return null;
        }
        /**
         * Parses items in JSON formats and attaches them to the menu.
         * @param {Array.<JSON>} items List of JSON menu items.
         */
        parseItems(items) {
            let hidden = items.map(x => [this.parseItem.bind(this)(x), x.hidden]);
            hidden.forEach(x => x[1] && x[0].hide());
        }
        /**
         * Parses items in JSON formats and attaches them to the menu.
         * @param {Array.<JSON>} items List of JSON menu items.
         * @return {}
         */
        parseItem(item) {
            const parseMapping_ = {
                'checkbox': ContextMenu.Checkbox.parse,
                'command': ContextMenu.Command.parse,
                'label': ContextMenu.Label.parse,
                'radio': ContextMenu.Radio.parse,
                'rule': ContextMenu.Rule.parse,
                'submenu': ContextMenu.Submenu.parse
            };
            let func = parseMapping_[item['type']];
            if (func) {
                let menuItem = func(item, this);
                this.getItems().push(menuItem);
                if (item['disabled']) {
                    menuItem.disable();
                }
                return menuItem;
            }
        }
    }
    ContextMenu.AbstractMenu = AbstractMenu;
})(ContextMenu || (ContextMenu = {}));