JSDoc: Source: abstract_menu.js

# 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 = {}));