How to promise in Chrome extensions

The following setup of Message Passing for communicating JSON data from a content script to a popup script is pretty usual:

  chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
    if (sender.tab) {
      return;
    }
    switch (request) {
    case 'selected_count':
      const count = selected_count();
      console.log('selected_count:', count);
      sendResponse({
        data: count
      });
      break;
    case 'selected_items':
      const items = selected_items();
      console.log('selected_items:', items);
      sendResponse({
        data: items
      });
      break;
    case 'unselect_all':
      unselect_all();
      break;
    }
  });

However, if some ´items´ contain data that you get asynchronously (like an image), then the setup above will fail if those data are not loaded before the handler returns.

Unfortunately, ´Promise´s are the right tool for the job in this case, but you can’t use them right away, because you can’t send a promise back to the popup and let it handle that, because a message can’t contain a promise, because

A message can contain any valid JSON object (null, boolean, number, string, array, or [my annotation: POJO] object).

Fortunately, according to the documentation,

If you want to asynchronously use ´sendResponse´, add ´return true;´ to the ´onMessage´ event handler.

which you can do like I show in the rewrite below, where I use a ´Promise´ object to take care of the asynchronous bits:

  chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
    const KEEP_CHANNEL_OPEN = true;
    const CLOSE_CHANNEL = false;
    var result = CLOSE_CHANNEL;
    if (sender.tab) {
      return result;
    }
    switch (request) {
    case 'selected_count':
      const count = selected_count();
      console.log('selected_count:', count);
      sendResponse({
        data: count
      });
      break;
    case 'selected_items':
      selected_items().then(items => {
        console.log('selected_items:', items);
        sendResponse({
          data: items
        });
      });
      result = KEEP_CHANNEL_OPEN;
      break;
    case 'unselect_all':
      unselect_all();
      break;
    }
    return result;
  });

 

How to convert indented text to a collapsible list

In my article about How to setup a Multi Page Application in AngularJS, I wanted to show a directory structure. I thought I would wrap it into a PRE element, to easily glance at the containment hierarchy. I started by jotting down only folders and files that I needed to talk about, hoping to simplify my readers task to go through them. But soon I realized that that structure was exactly what I was trying to describe in the first place and it didn’t make much sense to intentionally leave out other meaningful folders and files, just because it would be a pain to read. So I understood I had to find a way to make folders toggle on click. That would allow me to show only a portion by default, and allow the reader to freely move around in the hierarchy.

I looked in the Internet for a ready made solution with these features:

  1. Input: indented text.
  2. Output: collapsible list.
  3. Option to open some folders by default.
  4. Easily injectable into a WordPress post.

I couldn’t find anything that suited my needs, so I embarked into building something myself.

First I found an ingenuous article about making a Pure CSS collapsible tree menu. But if a way to expand collapse unordered lists is just a couple of lines in jQuery, and I still needed some code for converting the indented text to an HTML list, better to stay in the JS realm for all the solution and not mess with CSS. However, I really enjoyed how that guy took advantage of checkboxes to keep track of the collapsing state of folders.

After a couple of days, I shared my Indentation to Toggling List project on GitHub.

https://github.com/aercolino/indentation-to-toggling-list#indentation-to-toggling-list