1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5/** 6 * @fileoverview Widget presenting context menus. 7 */ 8 9goog.provide('cvox.ContextMenuWidget'); 10 11goog.require('cvox.ChromeVox'); 12goog.require('cvox.OverlayWidget'); 13goog.require('cvox.UserEventDetail'); 14 15var CONTEXT_MENU_ATTR = 'contextMenuActions'; 16/** 17 * Return the list from a node or an ancestor. 18 * Note: If there are multiple lists, this well return the closest. 19 * @private 20 * @param {Object} node Node to extract from. 21 * @return {*} Extracted list. 22 */ 23var extractMenuList_ = function(node) { 24 var curr = node; 25 while (curr !== document) { 26 var menuListJSON = curr.getAttribute(CONTEXT_MENU_ATTR); 27 if (menuListJSON) { 28 return JSON.parse(menuListJSON); 29 } 30 curr = curr.parentNode; 31 } 32 return null; 33}; 34 35/** 36 * Gets the current element node. 37 * @private 38 * @return {Node} Current element node. 39 */ 40var getCurrentElement_ = function() { 41 var currNode = cvox.ChromeVox.navigationManager.getCurrentNode(); 42 while (currNode.nodeType !== Node.ELEMENT_NODE) { 43 currNode = currNode.parentNode; 44 } 45 return currNode; 46}; 47 48/** 49 * @constructor 50 * @extends {cvox.OverlayWidget} 51 */ 52cvox.ContextMenuWidget = function() { 53 goog.base(this, ''); 54 this.container_ = document.createElement('div'); 55 56 /** 57 * The element that triggered the ContextMenu. 58 * @private 59 * @type {Node} 60 */ 61 this.triggerElement_ = getCurrentElement_(); 62 63 /** 64 * List of menu items in the context menu. 65 */ 66 this.menuList = extractMenuList_(this.triggerElement_); 67 68 if (!this.menuList) { 69 console.log('No context menu found.'); 70 return; 71 } 72 73 this.menuList.forEach(goog.bind(function(menuItem) { 74 if (menuItem['desc'] || menuItem['cmd']) { 75 var desc = menuItem['desc']; 76 var cmd = menuItem['cmd']; 77 78 var menuElem = document.createElement('p'); 79 menuElem.id = cmd; 80 menuElem.textContent = desc; 81 menuElem.setAttribute('role', 'menuitem'); 82 this.container_.appendChild(menuElem); 83 } 84 }, this)); 85}; 86goog.inherits(cvox.ContextMenuWidget, cvox.OverlayWidget); 87 88/** 89 * @override 90 */ 91cvox.ContextMenuWidget.prototype.show = function() { 92 if (this.menuList) { 93 goog.base(this, 'show'); 94 this.host_.appendChild(this.container_); 95 } 96}; 97 98/** 99 * @override 100 */ 101cvox.ContextMenuWidget.prototype.getNameMsg = function() { 102 return ['context_menu_intro']; 103}; 104 105/** 106 * @override 107 */ 108cvox.ContextMenuWidget.prototype.onKeyDown = function(evt) { 109 var ENTER_KEYCODE = 13; 110 if (evt.keyCode == ENTER_KEYCODE) { 111 var currentNode = cvox.ChromeVox.navigationManager.getCurrentNode(); 112 var cmd = currentNode.parentNode.id; 113 114 /* Dispatch the event. */ 115 var detail = new cvox.UserEventDetail({customCommand: cmd}); 116 var userEvt = detail.createEventObject(); 117 this.triggerElement_.dispatchEvent(userEvt); 118 this.hide(); 119 120 evt.preventDefault(); 121 evt.stopPropagation(); 122 return true; 123 } else { 124 return goog.base(this, 'onKeyDown', evt); 125 } 126}; 127