Chrome extension interop

I’m working on a Chrome extension (written primarily in Elm) where I need to make use of the (chrome.omnibox API) and the chrome.bookmarks API. I have two issues where I need guidance:

Callback in JS listener callback
In my JS-code I can listen for omnibox-changes using “chrome.omnibox.onInputChanged.addListener(callback)”. The callback parameter should be a function that looks like this: function(string text, function suggest) {…};
I would like to handle this listener callback in Elm and call the “suggest” callback with my calculated suggestions. I have currently not found a way to do this using Elm ports, because they are async. How can I handle this type of listener callback in Elm?

Callbacks in calls to Bookmarks API
I can invoke most of the functions in the bookmarks API through messages sent through ports from Elm to JS, but I cannot easily associate a request result with a bookmark API response (provided async through callbacks). How can I better integrate this with Elm? I have investigated using native/kernel modules, but that seams dirty/wrong. How to best make such an integration?

You can co-ordinate calls to the omnibox API if you manage some state on the JS side. This lets you keep the function around while Elm is generating the suggestions.

var mostRecentCallback;
var app  = /* your program */;

chrome.omnibox.onInputChanged.addListener(function(text, suggest) {
  mostRecentCallback = suggest;
  app.ports.inputChanged.send(text);
});

app.ports.suggestion.subscribe(function(suggestions) {
  if (mostRecentCallback) {
    var callback = mostRecentCallback;
    mostRecentCallback = undefined;
    callback(suggestions);
  }
});

There are probably nicer ways to manage this than re-assigning global variables, but I think this demonstrates the idea. I don’t have enough details to understand your issue with bookmarks API. Does this example help you out there as well?

Could you pass the callback function into the Elm port, and leave it as a Value? Then when you’re ready to execute the callback, send it out another port, where JavaScript can call the function.

Omnibox API
Yes, this might fix my issue with the omnibox API. In the event of multiple consecutive “onInputChanged” events, will I be guaranteed that “mostRecentCallback” always will be the correct callback function (because of the single-threaded JS event-loop)? In other words, is it unnecessary to do something to correlate messages received through the “suggestions” port with a stored callback function?

Bookmarks API
If I e.g. sends multiple “search” messages from JS to Elm (through a port), each call to the bookmark search function will result in a callback function being called with the result. I can of course send that back to Elm through a port, but if chrome performs the bookmark search on another (worker) thread I will have to correlate search requests with search results in Elm. But it might be that I overthink this and that things are simpler than I think because of the single-threaded nature of JS. I will do some experiments to see if I can assume that the response events (sent from JS to Elm) will come back in the same order that I sent request events (from Elm to JS).

You probably should add some defense against outdated suggestions. I don’t think that ordering can be guaranteed. You can track the mostRecentText and use that information in the JS if statement. You’ll just want to make sure you send it through the outgoing port as well.

I’d recommend against sending the function itself through the port since you’ll have trouble using the Elm debugger afterwards.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.