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