Error in Response to Tabs.getcurrent: Typeerror: Cannot Read Property 'id' of Undefined Extension

Working with the Tabs API

Tabs let a user open several spider web pages in their browser window and then switch between those web pages. With the Tabs API, yous can work with and manipulate these tabs to create utilities that provide users with new means to work with tabs or to deliver the features of your extension.

In this how-to article we'll wait at:

  • Permissions needed to use the Tabs API.
  • Discovering more almost tabs and their properties using tabs.query.
  • Creating, duplicating, moving, updating, reloading, and removing tabs.
  • Manipulating a tab'southward zoom level.
  • Manipulating a tab's CSS.

We then conclude by looking at some other, miscellaneous features offered by the API.

Note: In that location are some Tab API features covered elsewhere. These are the methods you tin use to manipulate tab content with scripts (tabs.connect, tabs.sendMessage, and tabs.executeScript). If you want more than data on these methods, encounter the Concepts article Content scripts and the how-to guide Modify a web page.

Permissions and the Tabs API

For the bulk of the Tabs API functions you lot don't need any permissions; still, there are some exceptions:

  • "tabs" permission is needed to access the Tab.url, Tab.title, and Tab.favIconUrl properties of the Tab object. In Firefox, you too demand "tabs" to perform a query by URL.
  • Host permission is needed for tabs.executeScript() or tabs.insertCSS().

The following is how you might request "tabs" permission in your extension's manifest.json file:

                                  "permissions"                  :                  [                  "<all_urls>"                  ,                  "tabs"                  ]                  ,                              

This asking gives y'all use of all Tabs API characteristic on all website your user visits. At that place is too an alternative approach for requesting permissions to employ tabs.executeScript() or tabs.insertCSS() where you don't need host permission, in the class of "activeTab". This permission provides the aforementioned rights as "tabs" with <all_urls>, but with two restrictions:

  • the user must interact with the extension through its browser or page action, context menu, or shortcut key.
  • it but grants permission within the active tab.

The benefit of this approach is the user won't get a permissions warning proverb your extension can "Access your data for all websites". This is considering <all_urls> permission gives an extension the ability to execute scripts in any tab, any fourth dimension it likes, whereas "activeTab" is limited to allowing the extension to perform a user requested action in the current tab.

Discovering more about tabs and their properties

At that place will exist occasions when yous want to get a list of all the tabs in all the browser windows. Other times you lot might want to discover a subset of tabs that match some specific criteria, such as those opened from a specific tab or displaying pages from a particular domain. And once you lot have your list of tabs, y'all'll probably want to know more than about their properties.

This is where tabs.query() comes in. Used lone to get all tabs or taking the queryInfo object—to specify query criteria such as whether the tab is active, in the current window, or ane or more of 17 criteria—tabs.query() returns an array of tabs.Tab objects containing information about the tabs.

Where you want data almost the current tab only, you tin get a tabs.Tab object for that tab using tabs.getCurrent(). If you accept a tab's ID, yous can get its tabs.Tab object using tabs.get().

How to example

To run across how tabs.query() and tabs.Tab are used, let'southward walk through how the tabs-tabs-tabs case adds the list of "switch to tabs" to its toolbar button popup.

The tabs toolbar menu showing the switch to tap area

manifest.json

Hither is the manifest.json:

                                          {                      "browser_action"                      :                      {                      "browser_style"                      :                      true                      ,                      "default_title"                      :                      "Tabs, tabs, tabs"                      ,                      "default_popup"                      :                      "tabs.html"                      }                      ,                      "description"                      :                      "A list of methods you can perform on a tab."                      ,                      "homepage_url"                      :                      "https://github.com/mdn/webextensions-examples/tree/master/tabs-tabs-tabs"                      ,                      "manifest_version"                      :                      2                      ,                      "proper noun"                      :                      "Tabs, tabs, tabs"                      ,                      "permissions"                      :                      [                      "tabs"                      ]                      ,                      "version"                      :                      "1.0"                      }                                      

Note:

  • tabs.html is defined as the default_popup in browser_action. It is displayed whenever the user clicks the extension'southward toolbar icon.
  • Permissions includes tabs. This is needed to support the tab list characteristic, as the extension reads the championship of the tabs for display in the popup.
tabs.html

tabs.html defines the content of the extension's popup:

                                                                  <!                        DOCTYPE                        html                        >                                                                                              <html                        >                                                                                              <head                        >                                                                                              <meta                        charset                                                  =                          "utf-eight"                                                >                                                                                              <link                        rel                                                  =                          "stylesheet"                                                href                                                  =                          "tabs.css"                                                />                                                                                              </caput                        >                                                                                              <body                        >                                                                                              <div                        class                                                  =                          "panel"                                                >                                                                                              <div                        form                                                  =                          "panel-section panel-section-header"                                                >                                                                                              <div                        class                                                  =                          "text-section-header"                                                >                      Tabs-tabs-tabs                                                  </div                        >                                                                                              </div                        >                                                                                              <a                        href                                                  =                          "#"                                                id                                                  =                          "tabs-movement-beginning"                                                >                      Move active tab to the beginning of the window                                                  </a                        >                                                                                              <br                        >                                            <!--     Define the other menu items     -->                                                                        <div                        class                                                  =                          "switch-tabs"                                                >                                                                                              <p                        >                      Switch to tab                                                  </p                        >                                                                                              <div                        id                                                  =                          "tabs-list"                                                >                                                                                              </div                        >                                                                                              </div                        >                                                                                              </div                        >                                                                                              <script                        src                                                  =                          "tabs.js"                                                >                                                                                                                    </script                        >                                                                                              </body                        >                                                                                              </html                        >                                                            

This does the following:

  1. The menu items are declared.
  2. An empty div with the ID tabs-list is declared to contain the list of tabs.
  3. tabs.js is called.
tabs.js

In tabs.js, we'll see how the listing of tabs is congenital and added to the popup.

Outset, an result handler is added to execute listTabs() when tabs.html is loaded:

                certificate.                  addEventListener                  (                  "DOMContentLoaded"                  ,                  listTabs)                  ;                              

The offset thing that listTabs() does is to call getCurrentWindowTabs(). This is where tabs.query() is used to get a tabs.Tab object for the tabs in the current window:

                                  part                  getCurrentWindowTabs                  (                  )                  {                  return                  browser.tabs.                  query                  (                  {                  currentWindow                  :                  true                  }                  )                  ;                  }                              

Now, listTabs() is prepare to create the content for the popup.

To outset with:

  1. Grab the tabs-list div.
  2. Create a certificate fragment (into which the list volition be congenital).
  3. Gear up counters.
  4. Clear the content of the tabs-list div.
                                  role                  listTabs                  (                  )                  {                  getCurrentWindowTabs                  (                  )                  .                  then                  (                  (                  tabs                  )                  =>                  {                  permit                  tabsList                  =                  document.                  getElementById                  (                  'tabs-listing'                  )                  ;                  let                  currentTabs                  =                  certificate.                  createDocumentFragment                  (                  )                  ;                  let                  limit                  =                  v                  ;                  let                  counter                  =                  0                  ;                  tabsList.textContent                  =                  ''                  ;                              

Next, we'll create the links for each tab:

  1. Loops through the first 5 items from the tabs.Tab object.
  2. For each item, add a hyperlink to the document fragment.
    • The link's characterization—that is, its text—is gear up using the tab's title (or the id, if it has no championship).
    • The link'due south address is set using the tab's id.
                                  for                  (                  let                  tab                  of                  tabs)                  {                  if                  (                  !tab.agile                  &&                  counter                  <=                  limit)                  {                  let                  tabLink                  =                  document.                  createElement                  (                  'a'                  )                  ;                  tabLink.textContent                  =                  tab.title                  ||                  tab.id;                  tabLink.                  setAttribute                  (                  'href'                  ,                  tab.id)                  ;                  tabLink.classList.                  add                  (                  'switch-tabs'                  )                  ;                  currentTabs.                  appendChild                  (tabLink)                  ;                  }                  counter                  +=                  ane                  ;                  }                              

Finally, the certificate fragment is written to the tabs-list div:

                                  tabsList.                  appendChild                  (currentTabs)                  ;                  }                  )                  ;                  }                              

Working with the active tab

Some other related instance characteristic is the "Warning agile tab" info option that dumps all the tabs.Tab object properties for the agile tab into an alarm:

                                  else                  if                  (e.target.id                  ===                  "tabs-alertinfo"                  )                  {                  callOnActiveTab                  (                  (                  tab                  )                  =>                  {                  allow                  props                  =                  ""                  ;                  for                  (                  let                  detail                  in                  tab)                  {                  props                  +=                                      `                                          ${                      item                      }                                                              =                                                              ${                      tab[item]                      }                                                              \n                    `                                    ;                  }                  warning                  (props)                  ;                  }                  )                  ;                  }                              

Where callOnActiveTab() finds the agile tab object by looping through the tabs.Tab objects looking for the item with agile set:

                document.                  addEventListener                  (                  "click"                  ,                  function                  (                  e                  )                  {                  function                  callOnActiveTab                  (                  callback                  )                  {                  getCurrentWindowTabs                  (                  )                  .                  then                  (                  (                  tabs                  )                  =>                  {                  for                  (                  var                  tab                  of                  tabs)                  {                  if                  (tab.active)                  {                  callback                  (tab,                  tabs)                  ;                  }                  }                  }                  )                  ;                  }                  }                              

Creating, duplicating, moving, updating, reloading, and removing tabs

Having gathered information virtually the tabs you'll about likely want to do something with them—either to offer users features for manipulating and managing tabs or to implement functionality in your extension.

The post-obit functions are bachelor:

  • create a new tab (tabs.create()).
  • duplicate a tab (tabs.duplicate()).
  • remove a tab (tabs.remove()).
  • move a tab (tabs.move()).
  • update the tab's URL—finer browse to a new page—(tabs.update()).
  • reload the tab's page (tabs.reload()).

How to instance

The tabs-tabs-tabs example exercises all of these features except for updating a tab's URL The style in which these APIs are used is similar, so nosotros'll look at one of the more involved implementations, that of the "Move active tab to the first of the window list" option.

Only starting time, here is a demonstration of the feature in activity:

manifest.json

None of the functions require a permission to operate, and then at that place are no features in the manifest.json file that need to be highlighted.

tabs.html

tabs.html defines the "carte du jour" displayed in the popup, which includes the "Movement active tab to the beginning of the window list" choice, with a series of <a> tags grouped by a visual separator. Each menu item is given an id, which is used in tabs.js to determine which menu particular is existence requested.

                                                                                            <a                        href                                                  =                          "#"                                                id                                                  =                          "tabs-move-showtime"                                                >                      Motion active tab to the beginning of the window                                                  </a                        >                                                                                              <br                        >                                                                                              <a                        href                                                  =                          "#"                                                id                                                  =                          "tabs-movement-end"                                                >                      Move agile tab to the end of the window                                                  </a                        >                                                                                              <br                        >                                                                                              <div                        grade                                                  =                          "panel-department-separator"                                                >                                                                                              </div                        >                                                                                              <a                        href                                                  =                          "#"                                                id                                                  =                          "tabs-indistinguishable"                                                >                      Duplicate active tab                                                  </a                        >                                                                                              <br                        >                                                                                              <a                        href                                                  =                          "#"                                                id                                                  =                          "tabs-reload"                                                >                      Reload active tab                                                  </a                        >                                                                                              <br                        >                                                                                              <a                        href                                                  =                          "#"                                                id                                                  =                          "tabs-alertinfo"                                                >                      Alert active tab info                                                  </a                        >                                                                                              <br                        >                                                            
tabs.js

To implement the "carte" defined in tabs.html, tabs.js includes a listener for clicks in tabs.html:

                    document.                      addEventListener                      (                      "click"                      ,                      office                      (                      e                      )                      {                      function                      callOnActiveTab                      (                      callback                      )                      {                      getCurrentWindowTabs                      (                      )                      .                      then                      (                      (                      tabs                      )                      =>                      {                      for                      (                      var                      tab                      of                      tabs)                      {                      if                      (tab.active)                      {                      callback                      (tab,                      tabs)                      ;                      }                      }                      }                      )                      ;                      }                      }                                      

A series of if statements then look to match the id of the detail clicked.

This lawmaking snippet is for the "Motility active tab to the commencement of the window list" option:

                                          if                      (due east.target.id                      ===                      "tabs-move-first"                      )                      {                      callOnActiveTab                      (                      (                      tab,                        tabs                      )                      =>                      {                      var                      index                      =                      0                      ;                      if                      (                      !tab.pinned)                      {                      index                      =                      firstUnpinnedTab                      (tabs)                      ;                      }                      console.                      log                      (                                              `                        moving                                                                          ${tab.id}                                                                          to                                                                          ${index}                                                `                                            )                      browser.tabs.                      movement                      (                      [tab.id]                      ,                      {index}                      )                      ;                      }                      )                      ;                      }                                      

It's worth noting the utilize of console.log(). This enables y'all to output information to the debugger console, which can be useful when resolving issues found during development.

Example of the console.log output, from the move tabs feature, in the debugging console

The move code first calls callOnActiveTab() which in turn calls getCurrentWindowTabs() to get a tabs.Tab object containing the active window'southward tabs. It then loops through the object to find and return the active tab object:

                                          function                      callOnActiveTab                      (                      callback                      )                      {                      getCurrentWindowTabs                      (                      )                      .                      and so                      (                      (                      tabs                      )                      =>                      {                      for                      (                      var                      tab                      of                      tabs)                      {                      if                      (tab.active)                      {                      callback                      (tab,                      tabs)                      ;                      }                      }                      }                      )                      ;                      }                                      

Pinned tabs

A feature of tabs is that the user can pin tabs in a window. Pinned tabs are placed at the start of the tab list and cannot exist moved. This means that the earliest position a tab can move to is the first position after any pinned tabs. So, firstUnpinnedTab() is called to observe the position of the first unpinned tab by looping through the tabs object:

                                  function                  firstUnpinnedTab                  (                  tabs                  )                  {                  for                  (                  let                  tab                  of                  tabs)                  {                  if                  (                  !tab.pinned)                  {                  return                  tab.index;                  }                  }                  }                              

We now have everything needed to move the tab: the active tab object from which we tin can get the tab id and the position the tab is to be moved to. So, nosotros can implement the motion:

                browser.tabs.                  motility                  (                  [tab.id]                  ,                  {alphabetize}                  )                  ;                              

The remaining functions to duplicate, reload, create, and remove tabs are implemented similarly.

Manipulating a tab's zoom level

The next set of functions enable y'all to get (tabs.getZoom) and set (tabs.setZoom) the zoom level inside a tab. Yous can likewise call back the zoom settings (tabs.getZoomSettings) only, at the fourth dimension of writing, the ability to set the settings (tabs.setZoomSettings) wasn't available in Firefox.

The level of zoom can be between 30% and 500% (represented every bit decimals 0.3 to 5).

In Firefox the default zoom settings are:

  • default zoom level: 100%.
  • zoom mode: automatic (so the browser manages how zoom levels are set).
  • scope of zoom changes: "per-origin", meaning that when you visit a site again, it takes the zoom level set in your last visit.

How to case

The tabs-tabs-tabs example includes three demonstrations of the zoom characteristic: zoom in, zoom out, and reset zoom. Here is the feature in action:

Let'south take a look at how the zoom in is implemented.

manifest.json

None of the zoom functions crave permissions, so in that location are no features in the manifest.json file that need to be highlighted.

tabs.html

Nosotros have already discussed how the tabs.html defines the options for this extension, aught new or unique is done to provide the zoom options.

tabs.js

tabs.js starts past defining several constants used in the zoom lawmaking:

                                          const                      ZOOM_INCREMENT                      =                      0.2                      ;                      const                      MAX_ZOOM                      =                      5                      ;                      const                      MIN_ZOOM                      =                      0.three                      ;                      const                      DEFAULT_ZOOM                      =                      1                      ;                                      

It so uses the same listener we discussed earlier and so it tin can act on clicks in tabs.html.

For the zoom in feature, this runs:

                                          else                      if                      (e.target.id                      ===                      "tabs-add-zoom"                      )                      {                      callOnActiveTab                      (                      (                      tab                      )                      =>                      {                      var                      gettingZoom                      =                      browser.tabs.                      getZoom                      (tab.id)                      ;                      gettingZoom.                      then                      (                      (                      zoomFactor                      )                      =>                      {                      //the maximum zoomFactor is five, information technology tin't get higher                      if                      (zoomFactor                      >=                      MAX_ZOOM                      )                      {                      alert                      (                      "Tab zoom cistron is already at max!"                      )                      ;                      }                      else                      {                      var                      newZoomFactor                      =                      zoomFactor                      +                      ZOOM_INCREMENT                      ;                      //if the newZoomFactor is set to higher than the max accepted                      //information technology won't alter, and will never alert that it'south at maximum                      newZoomFactor                      =                      newZoomFactor                      >                      MAX_ZOOM                      ?                      MAX_ZOOM                      :                      newZoomFactor;                      browser.tabs.                      setZoom                      (tab.id,                      newZoomFactor)                      ;                      }                      }                      )                      ;                      }                      )                      ;                      }                                      

This lawmaking uses callOnActiveTab() to get the details of the active tab, then tabs.getZoom gets the tab's electric current zoom factor. The current zoom is compared to the defined maximum (MAX_ZOOM) and an alert issued if the tab is already at the maximum zoom. Otherwise, the zoom level is incremented just limited to the maximum zoom, then the zoom is set with tabs.getZoom.

Manipulating a tab'due south CSS

Another significant capability offered by the Tabs API is the ability to manipulate the CSS within a tab—add new CSS to a tab (tabs.insertCSS()) or remove CSS from a tab (tabs.removeCSS()).

This tin be useful, for instance, if you want to highlight certain page elements or alter the default layout of the page.

How to example

The apply-css example uses these features to add together a red border to the spider web page in the active tab. Here is the characteristic in activity:

Let's walk through how information technology'southward fix up.

manifest.json

The manifest.json requests permissions required to use the CSS features. You need either:

  • "tabs" permission and host permission; or,
  • "activeTab" permission.

The latter is the most useful, every bit it allows an extension to use tabs.insertCSS() and tabs.removeCSS() in the active tab when run from the extension's browser or page activeness, context menu, or a shortcut.

                                          {                      "clarification"                      :                      "Adds a page action to toggle applying CSS to pages."                      ,                      "manifest_version"                      :                      two                      ,                      "proper name"                      :                      "apply-css"                      ,                      "version"                      :                      "1.0"                      ,                      "homepage_url"                      :                      "https://github.com/mdn/webextensions-examples/tree/master/use-css"                      ,                      "background"                      :                      {                      "scripts"                      :                      [                      "groundwork.js"                      ]                      }                      ,                      "page_action"                      :                      {                      "default_icon"                      :                      "icons/off.svg"                      ,                      "browser_style"                      :                      true                      }                      ,                      "permissions"                      :                      [                      "activeTab"                      ,                      "tabs"                      ]                      }                                      

You lot will note that "tabs" permission is requested in addition to "activeTab". This additional permission is needed to enable the extension's script to access the tab's URL, the importance of which nosotros'll meet in a moment.

The other primary features in the manifest.json file are the definition of:

  • a background script, which starts running as soon as the extension is loaded.
  • a "page activeness", which defines an icon to exist added to the browser's address bar.
background.js

On startup, background.js sets some constants to ascertain the CSS to be practical, titles for the "page action", and a list of protocols the extension will work in:

                                          const                      CSS                      =                      "trunk { border: 20px solid red; }"                      ;                      const                      TITLE_APPLY                      =                      "Apply CSS"                      ;                      const                      TITLE_REMOVE                      =                      "Remove CSS"                      ;                      const                      APPLICABLE_PROTOCOLS                      =                      [                      "http:"                      ,                      "https:"                      ]                      ;                                      

When outset loaded, the extension uses tabs.query() to get a listing of all the tabs in the electric current browser window. Information technology then loops through the tabs calling initializePageAction().

                                          var                      gettingAllTabs                      =                      browser.tabs.                      query                      (                      {                      }                      )                      ;                      gettingAllTabs.                      so                      (                      (                      tabs                      )                      =>                      {                      for                      (                      let                      tab                      of                      tabs)                      {                      initializePageAction                      (tab)                      ;                      }                      }                      )                      ;                                      

initializePageAction uses protocolIsApplicable() to decide whether the active tab'southward URL is i the CSS can be applied to:

                                          role                      protocolIsApplicable                      (                      url                      )                      {                      var                      ballast                      =                      certificate.                      createElement                      (                      'a'                      )                      ;                      anchor.href                      =                      url;                      return                      APPLICABLE_PROTOCOLS                      .                      includes                      (ballast.protocol)                      ;                      }                                      

Then, if the example can act on the tab, initializePageAction() sets the tab'south pageAction (navigation bar) icon and championship to use the "off" versions before making the pageAction visible:

                                          function                      initializePageAction                      (                      tab                      )                      {                      if                      (                      protocolIsApplicable                      (tab.url)                      )                      {                      browser.pageAction.                      setIcon                      (                      {                      tabId                      :                      tab.id,                      path                      :                      "icons/off.svg"                      }                      )                      ;                      browser.pageAction.                      setTitle                      (                      {                      tabId                      :                      tab.id,                      title                      :                      TITLE_APPLY                      }                      )                      ;                      browser.pageAction.                      prove                      (tab.id)                      ;                      }                      }                                      

Next, a listener on pageAction.onClicked waits for the pageAction icon to be clicked, and calls toggleCSS when it is.

                    browser.pageAction.onClicked.                      addListener                      (toggleCSS)                      ;                                      

toggleCSS() gets the championship of the pageAction and and then takes the activeness described:

  • For "Employ CSS":
    • toggles the pageAction icon and title to the "remove" versions.
    • applies the CSS using tabs.insertCSS().
  • For "Remove CSS":
    • toggles the pageAction icon and title to the "use" versions.
    • removes the CSS using tabs.removeCSS().
                                          function                      toggleCSS                      (                      tab                      )                      {                      function                      gotTitle                      (                      title                      )                      {                      if                      (title                      ===                      TITLE_APPLY                      )                      {                      browser.pageAction.                      setIcon                      (                      {                      tabId                      :                      tab.id,                      path                      :                      "icons/on.svg"                      }                      )                      ;                      browser.pageAction.                      setTitle                      (                      {                      tabId                      :                      tab.id,                      title                      :                      TITLE_REMOVE                      }                      )                      ;                      browser.tabs.                      insertCSS                      (                      {                      code                      :                      CSS                      }                      )                      ;                      }                      else                      {                      browser.pageAction.                      setIcon                      (                      {                      tabId                      :                      tab.id,                      path                      :                      "icons/off.svg"                      }                      )                      ;                      browser.pageAction.                      setTitle                      (                      {                      tabId                      :                      tab.id,                      title                      :                      TITLE_APPLY                      }                      )                      ;                      browser.tabs.                      removeCSS                      (                      {                      code                      :                      CSS                      }                      )                      ;                      }                      }                      var                      gettingTitle                      =                      browser.pageAction.                      getTitle                      (                      {                      tabId                      :                      tab.id}                      )                      ;                      gettingTitle.                      and then                      (gotTitle)                      ;                      }                                      

Finally, to ensure that the pageAction is valid after each update to the tab, a listener on tabs.onUpdated calls initializePageAction() each time the tab is updated to check that the tab is withal using a protocol to which the CSS can be applied.

                    browser.tabs.onUpdated.                      addListener                      (                      (                      id,                        changeInfo,                        tab                      )                      =>                      {                      initializePageAction                      (tab)                      ;                      }                      )                      ;                                      

Another interesting abilities

At that place are a couple of other Tabs API features that don't fit into one of the before sections:

  • Capture the visible tab content with tabs.captureVisibleTab.
  • Discover the primary linguistic communication of the content in a tab using tabs.detectLanguage. This could be used, for case, to lucifer the language in your extension's UI with that of the folio information technology's running in.

Learn more than

wolfepurt1954.blogspot.com

Source: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Working_with_the_Tabs_API

0 Response to "Error in Response to Tabs.getcurrent: Typeerror: Cannot Read Property 'id' of Undefined Extension"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel