# Pass info,tab through Shortkey/command listener like with a context menu listener

**URL:** <https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849>\
**Category:** Development\
**Created:** [September 17, 2018, 12:21pm UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849 "2018-09-17T12:21:30Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![DavidZ](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@DavidZ](https://discourse.mozilla.org/u/DavidZ)\
**Post date:** [September 17, 2018, 12:21pm UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/1 "2018-09-17T12:21:30Z")

</div>

Hey guys,

I’m having troubles using shortkeys/commands.  
In my extension I use a context menu, doing this for example:

`browser.contextMenus.onClicked.addListener(contextMenuAction);`

`browser.contextMenus.create({`  
`id: "1 Host Connect",`  
`title: "1 Host Connect",`  
`contexts: ["selection"]`  
`});`

`function contextMenuAction(info, tab) {`  
`switch (info.menuItemId) {`  
`case "1 Host Connect":`  
`browser.tabs.create({index: 1,url: "xyz://"+info.selectionText.trim()+"/"});`  
`break;`  
`}`  
`}`

That works well and as expected. Now I want to achieve the same thing with a shortcut using commands.  
So I defined ALT+1 for the above context menu point action. But I’m having troubles making it work, passing the same information as with browser.contextMenus.onClicked.addListener(contextMenuAction), meaning tab,info.

How can I achieve the same result uPreformatted textsing commands? Doing something like this doesn’t work since info and tab are not defined:

`function HotkeyContextMenuAction(info, tab) {`  
`browser.tabs.create({index: 1,url: "xyz://"+info.selectionText.trim()+"/"});`  
`}`

`browser.commands.onCommand.addListener(function(command,info,tab) {`  
`if (command == "1 Host Connect") {`  
`console.log('HOTKEY');`  
`HotkeyContextMenuAction(info,tab);`  
`}`  
`});`

Now, I am a total beginner when it comes to extension development, so please bear with me.  
Many thanks i advance!!!

Kind regards,  
David

---

<div class="post-metadata">

**Author:** ![freaktechnik](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/freaktechnik/32/37766_2.png) [@freaktechnik](https://discourse.mozilla.org/u/freaktechnik)\
**Post date:** [September 17, 2018, 12:32pm UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/2 "2018-09-17T12:32:11Z")

</div>

You can get the currently focused tab using the `browser.tabs` API, since that’s likely the tab the shortcut should be executed in. To get the selected text you will have to inject a script that gets the text and returns it to you. `browser.tabs.execScript` should be fine for that. You’ll also need the `activeTab` permission to do that easily.

---

<div class="post-metadata">

**Author:** ![DavidZ](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@DavidZ](https://discourse.mozilla.org/u/DavidZ)\
**Post date:** [September 17, 2018, 2:12pm UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/3 "2018-09-17T14:12:49Z")

</div>

I tried the following:

```
browser.commands.onCommand.addListener(function(command) {
  if (command == "1 Host Connect") {
     console.log('HOTKEY');
     console.log(command);
     browser.tabs.executeScript({
     code: `console.log('SELECTION: '+window.getSelection().toString());`
      });
  }
});

```

but the string appears to be empty… ☹

---

<div class="post-metadata">

**Author:** ![NilkasG](https://avatars.discourse-cdn.com/v4/letter/n/0ea827/32.png) [@NilkasG](https://discourse.mozilla.org/u/NilkasG)\
**Post date:** [September 17, 2018, 8:02pm UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/4 "2018-09-17T20:02:29Z")

</div>

So the page debugger shows `'SELECTION: '` but not the text you selected in the top frame of that tab? That would be odd …

---

<div class="post-metadata">

**Author:** ![DavidZ](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@DavidZ](https://discourse.mozilla.org/u/DavidZ)\
**Post date:** [September 18, 2018, 6:02am UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/5 "2018-09-18T06:02:56Z")

</div>

Exactly!! Output is:

```
HOTKEY 
1 Host Connect 
SELECTION:
```

---

<div class="post-metadata">

**Author:** ![DavidZ](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@DavidZ](https://discourse.mozilla.org/u/DavidZ)\
**Post date:** [September 18, 2018, 6:07am UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/6 "2018-09-18T06:07:31Z")

</div>

Ok… So it actually does works just not where I need it to work!  
If I execute the code via shortcut on a regular html page it works fine, the string is shown.  
But I’ll be using the extension with an icinga2 ([https://github.com/Icinga/icinga2](https://github.com/Icinga/icinga2)) webpage. That’s where I was testing it before and there it doesn’t work!! Don’t know why though…  
Maybe you guys have an idea???

---

<div class="post-metadata">

**Author:** ![DavidZ](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@DavidZ](https://discourse.mozilla.org/u/DavidZ)\
**Post date:** [September 18, 2018, 6:24am UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/7 "2018-09-18T06:24:45Z")

</div>

When I inspect the page element (again, don’t know anything about html whatsoever…) I see:

```
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

```

When I inspect the text that I’m selecting and trying to get through my extension I see:

 ![extension](https://us1.discourse-cdn.com/flex001/uploads/mozilla/original/3X/a/3/a36c042af8ded67b6cf3d686eb77a8111e5aee22.jpeg)

Does that information somehow explain why it doesn’t work?

---

<div class="post-metadata">

**Author:** ![Mittineague](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/mittineague/32/23743_2.png) [@Mittineague](https://discourse.mozilla.org/u/Mittineague)\
**Post date:** [September 18, 2018, 6:52am UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/8 "2018-09-18T06:52:47Z")

</div>

What do you get if you temporarily change the line to

```auto
code: `console.log('SELECTION: ' + typeof window.getSelection().toString());`

```

---

<div class="post-metadata">

**Author:** ![DavidZ](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@DavidZ](https://discourse.mozilla.org/u/DavidZ)\
**Post date:** [September 18, 2018, 7:02am UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/9 "2018-09-18T07:02:54Z")

</div>

Then I’ll get:

```
SELECTION: string

```

No matter which string I select on the page, result is always the same!

---

<div class="post-metadata">

**Author:** ![Mittineague](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/mittineague/32/23743_2.png) [@Mittineague](https://discourse.mozilla.org/u/Mittineague)\
**Post date:** [September 18, 2018, 8:23am UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/10 "2018-09-18T08:23:49Z")

</div>

Well, that’s better than null or undefined, but not much help.

I’m guessing because the text is in a child element you need to use `selectAllChildren()`

> **[Selection: selectAllChildren() method - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/Selection/selectAllChildren)**
>
> The Selection.selectAllChildren() method adds all the
> children of the specified node to the selection. Previous selection is lost.

eg. maybe

```auto
code: `console.log('SELECTION: ' + window.getSelection().selectAllChildren().toString());`

```

---

<div class="post-metadata">

**Author:** ![DavidZ](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@DavidZ](https://discourse.mozilla.org/u/DavidZ)\
**Post date:** [September 18, 2018, 2:33pm UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/11 "2018-09-18T14:33:23Z")

</div>

That doesn’t work. Console.log says that it need an argument:

```
Error: Not enough arguments to Selection.selectAllChildren.

```

Doc says:

```auto
footer = document.getElementById("footer");
window.getSelection().selectAllChildren(footer);

```

But I really have no idea what to do with document.getElementById

---

<div class="post-metadata">

**Author:** ![freaktechnik](https://sea1.discourse-cdn.com/flex001/user_avatar/discourse.mozilla.org/freaktechnik/32/37766_2.png) [@freaktechnik](https://discourse.mozilla.org/u/freaktechnik)\
**Post date:** [September 18, 2018, 2:36pm UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/12 "2018-09-18T14:36:16Z")

</div>

Pretty sure `selectAllChildren` changes the selection, especially since it says “Previous selection is lost”.

---

<div class="post-metadata">

**Author:** ![NilkasG](https://avatars.discourse-cdn.com/v4/letter/n/0ea827/32.png) [@NilkasG](https://discourse.mozilla.org/u/NilkasG)\
**Post date:** [September 18, 2018, 6:03pm UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/13 "2018-09-18T18:03:59Z")

</div>

I hinted at this before, but are you making the text selection in the same frame that you call `window.getSelection().toString()` in? If not, the returned string is expected to be empty.

Also, `console.log()` acceprs variable arguments and logs them all, you shouldn’t explicitly `+` them, which casts everything to strings (at least if one of them is a string).

---

<div class="post-metadata">

**Author:** ![DavidZ](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@DavidZ](https://discourse.mozilla.org/u/DavidZ)\
**Post date:** [September 19, 2018, 6:34am UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/14 "2018-09-19T06:34:01Z")

</div>

Gosh… this was (for me) so much easier with SDK. The extension worked well without having to worry about different frames, code injection and all that.

So let me try to understand this…  
A html page can have multiple frames… Top and child frames.  
The shortcut and its selection works on a regular html page because it doesn’t have child frames… there is just a top frame!?

However, on my icinga page there are child frames, so making the selection on the same frame (the top frame?) would return an empty string because the actual selection is on a child frame?

How can I access those child frames?  
I read that content scripts can be injected into all frames using something like:

```auto
"content_scripts": [
    {
      "js": ["my-script.js"],
      "matches": ["https://example.org/"],
      "match_about_blank": true,
      "all_frames": true
    }
  ]

```

My extension consist of a manifest.json and a background script icinga\_addon.js.

```auto
{
  "manifest_version": 2,
  "name": "Inc Icinga Shortcuts",
  "version": "1.0",
  "description": "Icinga Shortcuts",
  "permissions": ["contextMenus","activeTab"],
  
  "commands": {
    "1 Host Connect": {
      "suggested_key": {"default": "Alt+1" } ,
      "description": "1 Host Connect"
    }
   },
  
  "background": {
      "scripts": ["icinga_addon.js"] 
    }
}

```

How could I implement this?

Many thanks in advance… really appreciate it!!

---

<div class="post-metadata">

**Author:** ![NilkasG](https://avatars.discourse-cdn.com/v4/letter/n/0ea827/32.png) [@NilkasG](https://discourse.mozilla.org/u/NilkasG)\
**Post date:** [September 19, 2018, 12:21pm UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/15 "2018-09-19T12:21:56Z")

</div>

Yes, that is a pretty precise description for a possible, and given the type of page you are working on I think likely, cause of what you encounter here.

> How can I access those child frames?

You want to access the selected text in the background page, right?  
Haven’t tested it, but this should work:

```javascript
const pageSelection = (await Promise.all(
    (await browser.webNavigation.getAllFrames({ tabId, }))
    .map(({ frameId, }) => 
        browser.tabs.executeScript(tabId, { frameId, code: `window.getSelection().toString()`, })
        .catch(_ => '') //in production, avoid weird errors about uninitialized frames and stuff like that, but when debugging empty selection texts again, comment this line
    )
)).reduce((a, b) => a || b, '') || '';

```

You wouldn’t want static `content_scripts` in the manifest for this.

---

<div class="post-metadata">

**Author:** ![DavidZ](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@DavidZ](https://discourse.mozilla.org/u/DavidZ)\
**Post date:** [September 19, 2018, 8:22pm UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/16 "2018-09-19T20:22:07Z")

</div>

Thx Niklas,

Couldn’t make it work yet. Debugger always claims that there is a missing ) in line

`const pageSelection = (await Promise.all(`

Don’t understand why yet. Will check it next thing tomorrow morning though…

---

<div class="post-metadata">

**Author:** ![NilkasG](https://avatars.discourse-cdn.com/v4/letter/n/0ea827/32.png) [@NilkasG](https://discourse.mozilla.org/u/NilkasG)\
**Post date:** [September 20, 2018, 1:14pm UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/17 "2018-09-20T13:14:54Z")

</div>

The error message isn’t that helpful. You have to putthe code in an `async` function:

```javascript
browser.commands.onCommand.addListener(async command => { switch (command) {
    case '1 Host Connect': {
        const { id: windowId, } = (await browser.windows.getLastFocused());
        const { id: tabId, } = (await (browser.tabs.query({ active: true, windowId, })))[0];
        const pageSelection = (await Promise.all(
            (await browser.webNavigation.getAllFrames({ tabId, }))
            .map(({ frameId, }) => 
                browser.tabs.executeScript(tabId, { frameId, code: `window.getSelection().toString()`, })
                .catch(_ => '') // in production, avoid weird errors about uninitialized frames and stuff like that, but when debugging empty selection texts again, comment this line
            )
        )).reduce((a, b) => a || b, '') || '';
        // use `pageSelection`
    } break;
    // other commands
} });

```

Again, net tested, but it is syntactically correct and should work.

---

<div class="post-metadata">

**Author:** ![DavidZ](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@DavidZ](https://discourse.mozilla.org/u/DavidZ)\
**Post date:** [September 21, 2018, 1:20pm UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/18 "2018-09-21T13:20:36Z")

</div>

Hi Niklas thank you once again!! I’m not getting an syntax errors anymore… but everything after const pageSelection doesn’t seem to fire…  
If I simply implement a  
`console.log('End host connect');`  
for  
`// use pageSelection`  
I’ll get nothing in the console… noerror either. Any idea?

---

<div class="post-metadata">

**Author:** ![NilkasG](https://avatars.discourse-cdn.com/v4/letter/n/0ea827/32.png) [@NilkasG](https://discourse.mozilla.org/u/NilkasG)\
**Post date:** [September 23, 2018, 4:21pm UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/19 "2018-09-23T16:21:53Z")

</div>

Huh. Not really. I’d throw a bunch of `console.log`s in there and see what happens:

> **code with logging**
>
> ```javascript
> browser.commands.onCommand.addListener(async command => { switch (command) {
> case '1 Host Connect': {
> const { id: windowId, } = (await browser.windows.getLastFocused());
> console.log(`windowId`, windowId);
> const { id: tabId, } = (await (browser.tabs.query({ active: true, windowId, })))[0];
> console.log(`tabId`, tabId);
> const pageSelection = (await Promise.all(
> (await browser.webNavigation.getAllFrames({ tabId, }))
> .map(async ({ frameId, }) => { try {
> console.log(`Checking frame ${frameId} in tab ${tabId} ...`);
> const selected = (await browser.tabs.executeScript(tabId, { frameId, code: `window.getSelection().toString()`, }));
> console.log(`Selection in frame ${frameId} in tab ${tabId}:`, selection);
> return selection;
> } catch (_) { console.error(_); return ''; } }) // in production, avoid weird errors about uninitialized frames and stuff like that, but when debugging empty selection texts again, comment this line
> )).reduce((a, b) => a || b, '') || '';
> console.info(`Selection in some frame in the currently active tab ${tabId}`: pageSelection);
> // use `pageSelection`
> } break;
> // other commands
> } });
> 
> ```

---

<div class="post-metadata">

**Author:** ![DavidZ](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@DavidZ](https://discourse.mozilla.org/u/DavidZ)\
**Post date:** [September 24, 2018, 8:50am UTC](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849/20 "2018-09-24T08:50:44Z")

</div>

It’s really odd…  
Implementing your code I only get:

```auto
windowId 5 icinga_addon.js:672:9
tabId 2 icinga_addon.js:674:9

```

Thought this is some weird Icinga thing again, but even on a regular html page I can’t get more output.

[Next page](https://discourse.mozilla.org/t/pass-info-tab-through-shortkey-command-listener-like-with-a-context-menu-listener/31849.md?page=2)
