1

I am building a chrome extension to load a random URL from your bookmarks bar when you open a new tab.

My app.js has the following code:

var bookmarksArray = [];

// Function to traverse the bookmarks tree and save URLs in bookmarksArray
function process_bookmark(bookmarks) {
  for (var i =0; i < bookmarks.length; i++) {
    var bookmark = bookmarks[i];
    if (bookmark.url) {
        bookmarksArray.push(bookmark.url);
    }

    if (bookmark.children) {
        process_bookmark(bookmark.children);
    }
  }
}

// Process all bookmarks of user
 function createbookmarksArray(){
    chrome.bookmarks.getTree(process_bookmark);
}

// Get random bookmark URL from array and load it
 function getBookmark(){
    window.location.href = bookmarksArray[Math.floor(Math.random()*bookmarksArray.length)];
}

// All functions to be called on Page Load
function onLoadFunctions(){
    createbookmarksArray();
    getBookmark();
 }

// Function to be run on page load
 document.addEventListener("DOMContentLoaded", function(event) {
onLoadFunctions();
});

Also my manifest.json asks for the newtab and bookmarks permissions. newtab is set to index.html which calls ap.js

When I run this extension, I get a "Your file was not found. It may have been moved or deleted.ERR_FILE_NOT_FOUND" error.

When I run window.location.href =bookmarksArray[Math.floor(Math.random()*bookmarksArray.length)]; in the console, it works perfectly fine.

Am I calling the functions wrong?

raj7desai
  • 26
  • 1
  • 8
  • Sounds like the new tab doesn't have access to app.js (which sounds right). Why open the new tab with index.html, and not just use the random bookmark instead? – Reinstate Monica Cellio Mar 28 '17 at 11:34
  • When you do finish this extension, i'd like have it. I frequently have a need for loading a random bookmark into my tabs. – Jack G Mar 28 '17 at 11:38
  • @Archer How do I do that? I need to provide a HTML page for the newtab parameter in my manifest.json. Also my HTML is as follows: ` Blank New Tab ` – raj7desai Mar 28 '17 at 11:43
  • @lolzerywowzery Will do :) Thanks for the support! – raj7desai Mar 28 '17 at 11:44
  • You can open a new tab from your code, and pass it a Url at the same time. The manifest just needs you to tell it you want permission to open new tabs. – Reinstate Monica Cellio Mar 28 '17 at 11:52
  • Possibly better duplicate: [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](http://stackoverflow.com/q/23667086) – Makyen Mar 28 '17 at 23:36

1 Answers1

3

All the Chrome API functions use callbacks. This means that when you call createbookmarksArray that just starts the process of getting bookmarks, but then it immediately calls getBookmark with an empty array.

chrome.bookmarks.getTree is asynchronous - when you call it that starts the process off, and the callback is called after it has finished. JS gives priority to inline code, so all of your current function will complete before that callback is fired, even if Chrome is able to get all the bookmarks instantly.

The best way to avoid this is to use async and await. The Chrome API doesn't support them directly, but you can use a library like chrome-extension-async to get it.

Then your code looks like this:

// Function to be run on page load
document.addEventListener("DOMContentLoaded", async event => {
    try {
        // await tells JS to continue after the callback has fired
        const bookmarkTree = await chrome.bookmarks.getTree();

        // Now flatten the collection and grab one at random
        const bookmarksArray = process_bookmark(bookmarkTree);
        const randomIndex = Math.floor(Math.random()*bookmarksArray.length);
        const randomBookmark = bookmarksArray[randomIndex];

        // Create a new tab with the URL
        await chrome.tabs.create({ url: randomBookmark });
    }
    catch(err){
         // Handle any error in the callbacks here
    }
});
Keith
  • 150,284
  • 78
  • 298
  • 434