1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "mozilla/dom/KeyboardEvent.h"
8 #include "mozilla/dom/KeyboardEventBinding.h"
9 #include "mozilla/dom/Element.h"
10 #include "nsIFrame.h"
11 #include "nsMenuBarFrame.h"
12 #include "nsMenuBarListener.h"
13 #include "nsMenuFrame.h"
14 #include "nsMenuPopupFrame.h"
15 #include "mozilla/dom/XULMenuElement.h"
16 #include "mozilla/dom/XULMenuElementBinding.h"
17 #include "nsXULPopupManager.h"
18 
19 namespace mozilla {
20 namespace dom {
21 
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)22 JSObject* XULMenuElement::WrapNode(JSContext* aCx,
23                                    JS::Handle<JSObject*> aGivenProto) {
24   return XULMenuElement_Binding::Wrap(aCx, this, aGivenProto);
25 }
26 
GetActiveChild()27 already_AddRefed<Element> XULMenuElement::GetActiveChild() {
28   nsMenuFrame* menu = do_QueryFrame(GetPrimaryFrame(FlushType::Frames));
29   if (menu) {
30     RefPtr<Element> el;
31     menu->GetActiveChild(getter_AddRefs(el));
32     return el.forget();
33   }
34   return nullptr;
35 }
36 
SetActiveChild(Element * arg)37 void XULMenuElement::SetActiveChild(Element* arg) {
38   nsMenuFrame* menu = do_QueryFrame(GetPrimaryFrame(FlushType::Frames));
39   if (menu) {
40     menu->SetActiveChild(arg);
41   }
42 }
43 
HandleKeyPress(KeyboardEvent & keyEvent)44 bool XULMenuElement::HandleKeyPress(KeyboardEvent& keyEvent) {
45   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
46   if (!pm) {
47     return false;
48   }
49 
50   // if event has already been handled, bail
51   if (keyEvent.DefaultPrevented()) {
52     return false;
53   }
54 
55   if (nsMenuBarListener::IsAccessKeyPressed(&keyEvent)) return false;
56 
57   nsMenuFrame* menu = do_QueryFrame(GetPrimaryFrame(FlushType::Frames));
58   if (!menu) {
59     return false;
60   }
61 
62   nsMenuPopupFrame* popupFrame = menu->GetPopup();
63   if (!popupFrame) {
64     return false;
65   }
66 
67   uint32_t keyCode = keyEvent.KeyCode();
68   switch (keyCode) {
69     case KeyboardEvent_Binding::DOM_VK_UP:
70     case KeyboardEvent_Binding::DOM_VK_DOWN:
71     case KeyboardEvent_Binding::DOM_VK_HOME:
72     case KeyboardEvent_Binding::DOM_VK_END: {
73       nsNavigationDirection theDirection;
74       theDirection = NS_DIRECTION_FROM_KEY_CODE(popupFrame, keyCode);
75       return pm->HandleKeyboardNavigationInPopup(popupFrame, theDirection);
76     }
77     default:
78       return pm->HandleShortcutNavigation(&keyEvent, popupFrame);
79   }
80 }
81 
OpenedWithKey()82 bool XULMenuElement::OpenedWithKey() {
83   nsMenuFrame* menuframe = do_QueryFrame(GetPrimaryFrame(FlushType::Frames));
84   if (!menuframe) {
85     return false;
86   }
87 
88   nsIFrame* frame = menuframe->GetParent();
89   while (frame) {
90     nsMenuBarFrame* menubar = do_QueryFrame(frame);
91     if (menubar) {
92       return menubar->IsActiveByKeyboard();
93     }
94     frame = frame->GetParent();
95   }
96   return false;
97 }
98 
99 }  // namespace dom
100 }  // namespace mozilla
101