browser_toolbox_textbox_context_menu.js (5183B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // HTML inputs don't automatically get the 'edit' context menu, so we have 7 // a helper on the toolbox to do so. Make sure that shows menu items in the 8 // right state, and that it works for an input inside of a panel. 9 10 const URL = "data:text/html;charset=utf8,test for textbox context menu"; 11 const textboxToolId = "testtool1"; 12 13 registerCleanupFunction(() => { 14 gDevTools.unregisterTool(textboxToolId); 15 }); 16 17 add_task(async function checkMenuEntryStates() { 18 info("Checking the state of edit menuitems with an empty clipboard"); 19 const toolbox = await openNewTabAndToolbox(URL, "inspector"); 20 21 emptyClipboard(); 22 23 // Make sure the focus is predictable. 24 const inspector = toolbox.getPanel("inspector"); 25 const onFocus = once(inspector.searchBox, "focus"); 26 inspector.searchBox.focus(); 27 await onFocus; 28 29 info("Opening context menu"); 30 const onContextMenuPopup = toolbox.once("menu-open"); 31 synthesizeContextMenuEvent(inspector.searchBox); 32 await onContextMenuPopup; 33 34 const textboxContextMenu = toolbox.getTextBoxContextMenu(); 35 ok(textboxContextMenu, "The textbox context menu is loaded in the toolbox"); 36 37 const cmdUndo = textboxContextMenu.querySelector("#editmenu-undo"); 38 const cmdDelete = textboxContextMenu.querySelector("#editmenu-delete"); 39 const cmdSelectAll = textboxContextMenu.querySelector("#editmenu-selectAll"); 40 const cmdCut = textboxContextMenu.querySelector("#editmenu-cut"); 41 const cmdCopy = textboxContextMenu.querySelector("#editmenu-copy"); 42 const cmdPaste = textboxContextMenu.querySelector("#editmenu-paste"); 43 44 is(cmdUndo.getAttribute("disabled"), "true", "cmdUndo is disabled"); 45 is(cmdDelete.getAttribute("disabled"), "true", "cmdDelete is disabled"); 46 is(cmdSelectAll.getAttribute("disabled"), "true", "cmdSelectAll is disabled"); 47 is(cmdCut.getAttribute("disabled"), "true", "cmdCut is disabled"); 48 is(cmdCopy.getAttribute("disabled"), "true", "cmdCopy is disabled"); 49 50 if (isWindows()) { 51 // emptyClipboard only works on Windows (666254), assert paste only for this OS. 52 is(cmdPaste.getAttribute("disabled"), "true", "cmdPaste is disabled"); 53 } 54 55 const onContextMenuHidden = toolbox.once("menu-close"); 56 if (Services.prefs.getBoolPref("widget.macos.native-context-menus", false)) { 57 info("Using hidePopup semantics because of macOS native context menus."); 58 textboxContextMenu.hidePopup(); 59 } else { 60 EventUtils.sendKey("ESCAPE", toolbox.win); 61 } 62 await onContextMenuHidden; 63 }); 64 65 add_task(async function automaticallyBindTexbox() { 66 info( 67 "Registering a tool with an input field and making sure the context menu works" 68 ); 69 gDevTools.registerTool({ 70 id: textboxToolId, 71 isToolSupported: () => true, 72 url: CHROME_URL_ROOT + "doc_textbox_tool.html", 73 label: "Context menu works without tool intervention", 74 build(iframeWindow, toolbox) { 75 this.panel = createTestPanel(iframeWindow, toolbox); 76 return this.panel.open(); 77 }, 78 }); 79 80 const toolbox = await openNewTabAndToolbox(URL, textboxToolId); 81 is(toolbox.currentToolId, textboxToolId, "The custom tool has been opened"); 82 83 const doc = toolbox.getCurrentPanel().document; 84 await checkTextBox(doc.querySelector("input[type=text]"), toolbox); 85 await checkTextBox(doc.querySelector("textarea"), toolbox); 86 await checkTextBox(doc.querySelector("input[type=search]"), toolbox); 87 await checkTextBox(doc.querySelector("input:not([type])"), toolbox); 88 await checkNonTextInput(doc.querySelector("input[type=radio]"), toolbox); 89 }); 90 91 async function checkNonTextInput(input, toolbox) { 92 let textboxContextMenu = toolbox.getTextBoxContextMenu(); 93 ok(!textboxContextMenu, "The menu is closed"); 94 95 info( 96 "Simulating context click on the non text input and expecting no menu to open" 97 ); 98 const eventBubbledUp = new Promise(resolve => { 99 input.ownerDocument.addEventListener("contextmenu", resolve, { 100 once: true, 101 }); 102 }); 103 synthesizeContextMenuEvent(input); 104 info("Waiting for event"); 105 await eventBubbledUp; 106 107 textboxContextMenu = toolbox.getTextBoxContextMenu(); 108 ok(!textboxContextMenu, "The menu is still closed"); 109 } 110 111 async function checkTextBox(textBox, toolbox) { 112 let textboxContextMenu = toolbox.getTextBoxContextMenu(); 113 ok(!textboxContextMenu, "The menu is closed"); 114 115 info( 116 "Simulating context click on the textbox and expecting the menu to open" 117 ); 118 const onContextMenu = toolbox.once("menu-open"); 119 synthesizeContextMenuEvent(textBox); 120 await onContextMenu; 121 122 textboxContextMenu = toolbox.getTextBoxContextMenu(); 123 ok(textboxContextMenu, "The menu is now visible"); 124 125 info("Closing the menu"); 126 const onContextMenuHidden = toolbox.once("menu-close"); 127 if (Services.prefs.getBoolPref("widget.macos.native-context-menus", false)) { 128 info("Using hidePopup semantics because of macOS native context menus."); 129 textboxContextMenu.hidePopup(); 130 } else { 131 EventUtils.sendKey("ESCAPE", toolbox.win); 132 } 133 await onContextMenuHidden; 134 135 textboxContextMenu = toolbox.getTextBoxContextMenu(); 136 ok(!textboxContextMenu, "The menu is closed again"); 137 }