0

I'm learning how to make an extension (for Firefox).

This add-on reads the youtube main page (https://www.youtube.com/) and get the visible videos on it. From those videos, I'm able to extract the video ID, title, duration of the video, channel name and channel ID.

With this data, I want to show a pop-up dialog with a HTML table that has the obtained info as folows:

Channel No. of videos
NationSquid 1
Numberphile 4
JhonNroses 8
HugoX Chugox 3

[...and so on]


My manifest.json:

{
  "manifest_version": 2,
  "name": "Ejemplo",
  "version": "1.0",
  "description": "Inspeccionar elementos de youtube.com.",
  "homepage_url": "https://github.com/mdn/webextensions-examples/tree/main/beastify",
  "icons": {
    "48": "icons/border-48.png"
  },
  "applications": {
    "gecko": {
      "id": "[email protected]"
    }
  },
  "permissions": [
    "tabs",
    "activeTab",
    "storage",
    "background"
  ],
  "browser_action": {
    "default_icon": "icons/beasts-32.png",
    "default_title": "Obtain YouTube Info",
    "default_popup": "popup/results.html",
    "browser_style": true
  },
  "content_scripts": [
    {
      "matches": [
        "https://*.youtube.com/"
      ],
      "js": [
        "jquery-1.9.1.min.js",
        "Ejemplo.js",
        "/code/functions.js"
      ]
    }
  ],
  "background": {
    "scripts": [
      "/code/popup.js"
    ]
  }
}

My results.html file = which is the pop-up:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
    <div id="allVideos"><i>Loading...</i></div>
    <script src="../jquery-1.9.1.min.js"></script>
    <script src="../code/popup.js"></script>
</body>
</html>

My popup.js file = the file that writes the HTML code in the "results.html" file:

(function () {
  console.log("Entró");
  init_code();
})();

/**
 * Function that initializes the page.
 */
function init_code() {
  try {
    // Initial variables: 
    var html_code = "";

    // Get all videos: 
    // Source: https://www.sitepoint.com/create-firefox-add-on/
    browser.storage.sync.get(['all_videos'])
      .then((result) => {
        if (result.hasOwnProperty('all_videos') && result.all_videos) {
          if (result.all_videos && result.all_videos.length) {
            // Build initial HTML table code: 
            html_code += `<table id="myTable"><tr><th>Thumbnail</th><th>Title</th><th>Channel_ID</th></tr>`;

            // Loop over the items and build the HTML with their data: 
            result.all_videos.forEach((item) => {
              html_code += appendItem(item);
            });

            // Finish the HTML table code: 
            html_code += "</table>";

          } else {
            // Show: "no items available": 
            html_code = '<strong>No videos are stored on the localStorage.</strong>';
          }
        } else {
          // Show: "no items available": 
          html_code = '<strong>No videos are stored on the localStorage.</strong>';
        }
      }, onErrorDetails);

    console.log("Ok!");

    // Show the results: 
    document.getElementById("allVideos").innerHTML = html_code;
  } catch (ex) {
    console.log("Error at the popup");
    console.log("Error: " + ex.message);
    console.log("Stack: " + ex.stack);
  }
}

/**
 * Function that builds the HTML to be added on the main HTML div.
 * @param {object} item The item (i.e, the object that contains the video's data).
 * @returns string
 */
function appendItem(item) {
  return `<tr><img src='${item.Thumbnail}' alt='${item.Title}' /></tr><tr><span>${item.Title}</span></tr><tr><span>${item.Channel}</span></tr><tr><span>${item.Channel_ID}</span></tr>`;
}

/**
 * Function that handles the error(s) - if any - when the info is obtained from the localStorage.
 * @param {object} error_dt The object with the error details.
 */
function onErrorDetails(error_dt) {
  console.log("Error!");
  console.log(error_dt);
}

My goal is:

I want the add-on shows a pop-up dialog with the HTML I want to specify - in this case, a HTML <table> as shown in the example above.

My current issue is:

Despite all variations made in the manifest.json file, the popup.js code is not triggered at all.

Current result: Shows the "Loading..." text embed in the HTML file, when it should build the table HTML.

Loading popup-without modifications

I've read about the user interface and popups in the documentation; however, I followed step-by-step the different tutorial(s) I've found, but, I haven't found a reason about why this code is not running - no even errors or logs in the console.

Can anyone point me to the right path to achive this goal?


1 In the documentation - section "specifying a popup", the add-on uses a base HTML with a pre-defined HTML, but, I haven't found if this "base HTML" can be modified with javascript.

3
  • Remove content_scripts and use browser.tabs.executeScript in the popup's script.
    – woxxom
    Commented Jul 26 at 16:48
  • @woxxom thanks for the comment. I'm looking to open a pop-up like AdBlock does. I've searched and changed my manifest.json as shown in this answer for use browser.tabs.executeScript, but I got errors due to permissions (those errors are not from my code, though). Is anything else I should investigate? Commented Jul 26 at 18:11
  • @woxxom Looks like the problem I'm facing (despite changing the manifest.json and making more tests) its very similar to this question - I've even posted a question here = the browser.tabs, query, etc just does not trigger at all. Commented Jul 29 at 17:19

1 Answer 1

0

Ok, I finally figure it out.

The key parts are:

  • Use browser.storage.sync.set and browser.storage.sync.get for use the localStorage. I did follow this tutorial.
  • Load correctly the path of the files in both, the manifest.json and popup.html files = the files that uses your resources. In my case, I didn't set the relative path to the .js file correctly = resulting in not being able to use javascript code at all.
  • The .js file that executes your code in your popup.html file (in my case, the popup.js file) must be added all (including functions) inside de $(document).ready(() => { code block (or its equivalent)1.

I share my manifest.json file:

{
  "manifest_version": 2,
  "name": "Ejemplo",
  "version": "1.0",
  "description": "Inspeccionar elementos de youtube.com.",
  "homepage_url": "https://github.com/mdn/webextensions-examples/tree/main/beastify",
  "icons": {
    "48": "icons/border-48.png"
  },
  "applications": {
    "gecko": {
      "id": "[email protected]"
    }
  },
  "permissions": [
    "tabs",
    "activeTab",
    "storage"
  ],
  "browser_action": {
    "default_icon": "icons/beasts-32.png",
    "default_title": "Obtain YouTube Info",
    "default_popup": "popup/results.html",
    "browser_style": true
  },
  "content_scripts": [
    {
      "matches": [
        "https://*.youtube.com/"
      ],
      "js": [
        "jquery-1.9.1.min.js",
        "Ejemplo.js",
        "/code/functions.js",
        "/code/popup.js"
      ]
    }
  ]
}

results.html = my popup:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <link href="../css/popup.css" rel="stylesheet" />
</head>

<body>
    <table id="myTable">
        <tr>
            <th>Channel</th>
            <th>No. of videos</th>
        </tr>
    </table>
    <script src="../jquery-1.9.1.min.js"></script>
    <script src="../code/popup.js"></script>
</body>

</html>

popup.js = the file that creates the HTML and appends it to results.html:

$(document).ready(() => {

  // Source: https://www.sitepoint.com/create-firefox-add-on/
  browser.storage.sync.get(['all_videos']).then((result) => {
    // Loop over the items and build the HTML with their data: 
    result.all_videos.forEach((item) => {
      appendItem(item);
    });
  }, onErrorDetails);

  /**
 * Function that builds the HTML to be added.
 * @param {object} item The item (i.e, the object that contains the video's data).
 * @returns string
 */
  function appendItem(item) {

    // Append the row(s) to the table: 
    // Source: https://www.enablegeek.com/tutorial/jquery-add-row-to-table/
    $('#myTable tbody').append(`<tr>
                                  <td>
                                  <td><span>${item.channelName}</span></td>
                                  <td><span>${item.qtyVideos}</span></td>
                                </tr>`);
  }

  /**
 * Function that handles the error(s) - if any - when the info is obtained from the localStorage.
 * @param {object} error_dt The object with the error details.
 */
  function onErrorDetails(error_dt) {
    console.log("Error!");
    console.log(error_dt);
  }

});

1 I suspect this is due to the webpage lifecycle; for some reason, I could not use document.getElementById("...") - everytime I got undefined, so, instead, I have to use JQuery for append the HTML in construction - i.e: $('#myTable tbody').append(<my_string_html>); - see here how to append a row to a table using JQuery.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.