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