dangerous.beans
dangerous.beans

Reputation: 598

Firefox addon: Get an array of all bookmark folders

I'd like to be able to return an array of all a users bookmark folders from the root folder at any point in the tree.

This is the closest I've come which returns nothing of RESULT_TYPE_FOLDER:

function find_folders()
{
  var history = Cc["@mozilla.org/browser/nav-history-service;1"]
     .getService(Ci.nsINavHistoryService);

  var query = history.getNewQuery();
  var options = history.getNewQueryOptions();

  // Query users bookmarks, not history
  options.queryType = options.QUERY_TYPE_BOOKMARKS;

  // Execute the search and store results
  var result = history.executeQuery(query, options);

  // Open the root containerNode and open it
  var resultContainerNode = result.root;

  // OPEN resultContainerNode
  resultContainerNode.containerOpen = true;
  var folders = [];

  // Search results are now child items of this container?
  for (var i=0; i < resultContainerNode.childCount; ++i) {
    var childNode = resultContainerNode.getChild(i);

    if(childNode.type === childNode.RESULT_TYPE_FOLDER)
    {
      folders.push(childNode);
    }
  }

  // CLOSE resultContainerNode
  resultContainerNode.containerOpen = false;

  return folders;
};

find_folders();

If I remove this result type checking I get lots of URIs, some RESULT_TYPE_QUERYs, but no RESULT_TYPE_FOLDER:

childNode.type: 0
childNode.type: RESULT_TYPE_QUERY
childNode.title: Most Visited
childNode.type: 0
childNode.type: 0
childNode.type: 0
childNode.type: 0
childNode.type: 0
childNode.type: 0
childNode.type: 0
childNode.type: 0
childNode.type: 0
childNode.type: 0
childNode.type: RESULT_TYPE_QUERY
childNode.title: History

The documentation here: https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryQueryOptions#Query_type_constants suggests you can set:

excludeItems boolean This option excludes all URIs and separators from a bookmarks query. This would be used if you just wanted a list of bookmark folders and queries (such as the left pane of the places page). Ignored for queries over history. Defaults to false.

But setting this causes the query to return no results:

function find_folders()
{
  var history = Cc["@mozilla.org/browser/nav-history-service;1"]
     .getService(Ci.nsINavHistoryService);

  var query = history.getNewQuery();
  var options = history.getNewQueryOptions();

  options.queryType = options.QUERY_TYPE_BOOKMARKS;
  options.excludeItems = true; // Exclude everything that isn't a folder?
  // Execute the search and store results
  var result = history.executeQuery(query, options);

  // Open the root containerNode and open it
  var resultContainerNode = result.root;

  // OPEN resultContainerNode
  resultContainerNode.containerOpen = true;
  var folders = [];

  // Search results are now child items of this container?
  for (var i=0; i < resultContainerNode.childCount; ++i) {
    var childNode = resultContainerNode.getChild(i);
    folders.push(childNode);
  }

  // CLOSE resultContainerNode
  resultContainerNode.containerOpen = false;

  return folders;
};

find_folders(); // Returns nothing :C

Upvotes: 1

Views: 766

Answers (2)

dangerous.beans
dangerous.beans

Reputation: 598

Okay looks like I've run into a few bugs and limitations in the Firefox Places query interface.

1 - (bug?) setting query.setFolders([folder_array], 1) with the second paramater (folder count) to anything other than 1 causes no results. Setting it to 1 will only search the first folder from your array.

2 - (limitation) excludeItems works only if you specify folders to search into which isn't helpful :C

3 - (limitation/bug?) query.setSearchTerm(term) seems to not match folder names so I had to manually check them against the search term :Q__

Sketchy workaround solution is to create the array of folders to search and then search separately through each one, concatenating the results, like so:

bookmarkr_utilities.find_folders = function(search_term)
{
  bookmarkr_utilities.debug_log("find_folders()");
  bookmarkr_utilities.folders = [];


  var folders = [   bookmarkr_utilities.bmsvc_service().toolbarFolder
                  , bookmarkr_utilities.bmsvc_service().bookmarksMenuFolder
                  , bookmarkr_utilities.bmsvc_service().unfiledBookmarksFolder   ];


  for (var i = 0; i < folders.length; i++) 
  {
    bookmarkr_utilities.folders = bookmarkr_utilities.folders.concat(bookmarkr_utilities.find_inside_folder(search_term, folders[i]));
  }

  return bookmarkr_utilities.folders;
};

Helper function to actually run the search:

bookmarkr_utilities.find_inside_folder = function(search_term, search_folder)
{
  var history = Cc["@mozilla.org/browser/nav-history-service;1"]
     .getService(Ci.nsINavHistoryService);

  var result_folders = [];

  var query = history.getNewQuery();

  query.setFolders([search_folder], 1);

  var options = history.getNewQueryOptions();

  options.excludeItems = true; // exclude everything except folders
                               // only works when folders are set

  // Execute the search and store results
  var result = history.executeQuery(query, options);

  // Open the root containerNode and open it
  var resultContainerNode = result.root;
  resultContainerNode.containerOpen = true;

  // Search results are now child items of this container?
  bookmarkr_utilities.debug_log("resultContainerNode.childCount: " + resultContainerNode.childCount);
  for (var i=0; i < resultContainerNode.childCount; ++i) {
    var childNode = resultContainerNode.getChild(i);

    if(childNode.type === childNode.RESULT_TYPE_FOLDER)
    {
      // HACK HACK HACK
      if(search_term)
      {
        if(childNode.title.toLowerCase() == search_term.toLowerCase())
          result_folders.push(childNode);
      }
      // END HACK HACK HACK OH GOD
      else
      {
        result_folders.push(childNode);
      }
    }
  }

  // Close container
  resultContainerNode.containerOpen = false;

  return result_folders;
}

Upvotes: 1

MaK
MaK

Reputation: 21

excludeItems works only if you specify folders to search into, for example

query.setFolders([PlacesUtils.toolbarFolderId, PlacesUtils.bookmarksMenuFolderId,
                 PlacesUtils.unfiledBookmarksFolderId], 1);

It also doesn't return a flat list of folders, so you have to go through the results, open and collect contents recursively.

You are free to file an enhancement bug, if you have a good use-case to get a flat list of folders.

Finally, you are taking Places nodes out of the result and handing them out, this makes them zombie objects basically, would be better if you'd create your own object and add to it stuff you care about, like { title: node.title, uri: node.uri }, or whatever else (I just found a bug here related to this behavior and I'm going to file and fix it).

Upvotes: 2

Related Questions