Skip to content
This repository has been archived by the owner on Feb 26, 2022. It is now read-only.
Jordan Santell edited this page Jun 4, 2013 · 10 revisions

Places API JEP (WIP)

Overview

An API for Firefox Places (History and Bookmarks).

Current Hacking

Notes 6/3/2013

  • Don't expose an "update/refresh" method
  • Rename folders to groups -- more conceptual, and futureproofs if the UI of bookmarks is displayed differently
  • Make id property immutable
  • Robust query interface for bookmarks via .get({}, {}, …) have properties like tags, urls, and other bookmark fields. Will use several services to get the aggregate results. ANDs properties in a single query object, and ORs the results of several query objects (need intersection/union operators on bookmarks)
  • Always return a new data object, do not respect identity
  • Add a resolution function to save, in event of out-of-date bookmark:
save({}, { resolve: function (mine, theirs) {
  // If you want to clobber changes, just return mine
  // if out of date -- or can only overwrite something like
  // the tags property. Whatever is returned is saved.
  return mine;
}})
  • Remove createBookmark and similar methods (should just have Bookmark which instantiates a data structureish class)
  • Remove index on Bookmark items ????
  • Hide id???
  • Map v0 to v1 since a new bookmark will not have an updated time, so we'll need to map the initial save to the initial data structure to infer if conflict resolution is necessary
  • Remove delete/remove functions -- done via a variable like bookmark.removed = true and passed into save method
  • remove removeAllChildren and getChildren -- can be done with a query with a group property
  • Recursively save group dependencies when saving bookmarks if needed (save the parent if it doesn't exist while saving a bookmark)
  • remove isBookmarked -- can be done with a URL query
  • Support splats
  • Remove Tags module -- roll into module with Sets
  • Prevent duplicate creation (?)

Goals

  • Phase 1
    • Provide easy to use API for CRUD, querying, and tagging behaviour for bookmarks, folders, separaters (must have)
    • Hook Bookmark instances to platform observers (nsINavBookmarkObserver)
    • Provide easy to use API for CRUD, querying History and Bookmarks (nice to have)

Questions/Concerns

  • How are keywords used?
  • Should we have node-style callbacks when using the optional callback parameter instead of promises? function (err, res) {}
  • Should Backup/Restore be implemented? backup/restore

Proposed API

Bookmark

Bookmark contains static methods to create, update and manipulate bookmark items like bookmarks, folders and separators.

Functions

createBookmark(properties)
  • @param {Object|Array} properties
  • @return {Promise}

Takes an object of properties, or an array of objects and returns a promise for a Bookmark object. Upon creation, the item makes an asynchronous saves.

  • String title: required The name of the bookmark
  • String|URL url: required the url (either as a String or URL instance)
  • BookmarkItem|Number parent: The ID of the parent folder where the bookmark should live. (Default: ID of the menu folder)
  • Number index: The position of the Folder within its parent. Defaults to the last position. (Default: -1)
let { createBookmark } = require('bookmark');

createBookmark({
	title: 'Mozilla',
	url: 'http://www.mozilla.org
}).then(function (bookmark) {
	
})
createFolder(properties)
  • @param {Object|Array} properties
  • @return {Promise}

Takes an object of properties, or an array of objects and returns a a promise for a Folder object. Upon creation, the item makes an asynchronous saves.

  • String title: required The name of the bookmark
  • BookmarkItem|Number parent: The ID of the parent folder where the bookmark should live. (Default: ID of the menu folder)
  • Number index: The position of the Folder within its parent. Defaults to the last position. (Default: -1)
createSeparator(properties)
  • @param {Object|Array} properties
  • @return {Promise}

Takes an object of properties, or an array of objects and returns a a promise for a Separator object. Upon creation, the item makes an asynchronous saves.

  • BookmarkItem|Number parent: The ID of the parent folder where the separator should live. (Default: ID of the menu folder)
  • Number index: The position of the Folder within its parent. Defaults to the last position. (Default: -1)
save(items)
  • @param {Bookmark|Folder|Separator|Array} items
  • @return {Promise}

Pushes properties of items to their platform counterparts -- returns a promise that resolves to instances of these items upon saving.


let { save } = require('bookmarks');

createFolder(…).then(function (folder) {
	createBookmark({ url: 'http://foo', parent: folder, … })
	.then(function (bookmark) {
		// Now update bookmark's url to 'http://bar'
		bookmark.url	= 'http://bar';
		save(bookmark).then(function (bm) {
			// Now the bookmark on the platform
			// has been updated with url 'http://bar'
		})
	})
})

update(items)
  • @param {Bookmark|Folder|Separator|Array} items
  • @return {Promise}

THIS NEEDS A BETTER NAME?

Updating items refreshes the properties of the instance with the most up-to-date properties from the host. Returns a promise that resolves to the instances upon completion.

let { update } = require('bookmarks');

let bookmark; 
createBookmark(…).then(function (bm) {
	// We store the saved bookmark and use it later down the road…
	bookmark = bm;
});

// ..later..

// We update `bookmark` because another addon or
// the user could've changed it

update(bookmark).then(function (bm) {
	// Now the properties of `bookmark` are updated
	// if there were any changes
})


remove(item)
  • @param {Bookmark|Folder|Separator|Array} items
  • @return {Promise}

Removes the platform's bookmark based off of item's ID.

let { remove } = require('bookmark');

let item = someQueryReturningAnItem();

remove(item).then(function () {
  console.log('removed');
})
removeChildren(item)
  • @param {Folder|Array} folder
  • @return {Promise}

Removes all children from a Folder, also takes an array of folders.

getChildren(item)
  • @param {Folder} folder
  • @return {Promise}

Get all children from a Folder, or array of Folders.

let { getChildren } = require('bookmark');

getChildren(folder).then(function (children) {
	
});

getBookmarksByURL(urls)
  • @param {String|URL|Array} urls
  • @return {Promise}

Returns a promise that resolves to an array of Bookmarks.

getBookmarksByTag(tag)
  • @param {String|Array} tag
  • @return {Promise}

Returns a promise that resolves to an array of Bookmarks that have been tagged with tag.

isBookmarked(url)
  • @param {String|URL} url
  • @return {Promise}

Returns a promise that resolves to a boolean indicating whether or not the URL has been bookmarked.

Properties

These constants store the IDs of default folders and are used in other methods in Folder and Bookmark

  • Bookmark.MENU
  • Bookmark.PLACES
  • Bookmark.TAGS
  • Bookmark.TOOLBAR
  • Bookmark.UNSORTED

Bookmark Class

Properties
  • id readonly
  • index
  • title
  • url
  • parent

Folder Class

Properties
  • id readonly
  • index
  • title
  • parent
  • readonly (should this be implemented?)

Separator Class

Properties
  • id readonly
  • index

Tags

Tags are URL based, so if several bookmarks of http://mozilla.com exist, adding a tag of moz to this URL would add it to all bookmarks with that URL. This can be a utility to be used standalone for querying/editing tags, and also used within the Bookmarks module to tag bookmarks.

Functions

tag(url, tags)

Tags url with tags

  • @param {String|URL} url
  • @param {String|Array} tags
  • @return {Promise}
untag(url, tags)

Removes tags from url

  • @param {String|URL} url
  • @param {String|Array} tags
  • @return {Promise}
getURLsWithTag(tag)

Returns an array of URLs that are tagged with tag

  • @param {String|Array} tags
  • @return {Promise}
getTagsFromURL(url)

Returns an array of tags that match url

  • @param {String|URL|Array} url
  • @return {Promise}
var { Tags } = require('sdk/places/tags');
var url = 'http://mozilla.com';

Tags.tag(url, ['mozilla', 'javascript', 'jetpacks'])
  .then(Tags.untag(url, 'javascript'))
  .then(Tags.getURLsWithTag('mozilla'))
  .then(function (val) {
    val; // ['http://mozilla.com']
    return Tags.getTagsFromURL(url);
  })
  .then(function (val) {
    val; // ['mozilla', 'jetpacks'];
  });

History

Functions

query(options)
  • @param {Object} options
  • @return {Promise}

Returns a promise for an array of history items that match the query's options.

Options
  • String sort: A string to specify the type of sort to use. Possible options: 'title', 'date', 'url', 'visitCount', 'keyword', 'dateAdded', 'lastModified'. Default is unsorted.
  • Boolean ascending: Whether or not the sorted results should be ascending. Default is false, which returns the results in a descending order. Has no effect if sort is undefined.
  • Number count: Upper limit of how many items are returned. Default is no limit.
  • Date|Number from: Time relative from the epoch that history results should be limited to occuring after. Can accept a Date object, or milliseconds from the epoch. Default is from the epoch (all time).
  • Date|Number to: Time relative from the epoch that history results should be limited to occuring before. Can accept a Date object, or milliseconds from the epoch. Default is the current time.
  • String query: Search terms to match history results with query in its URL or title.
  • String domain: Limit results that originated from a specific domain. Can limit to when domain is only the host, like 'mozilla.org', or specify that subdomains are allowed like '*.mozilla.org'.
let { query } = require('sdk/places/history');

query({
  sort: 'date',
  count: 15,
  from: new Date('1/1/2006'),
  to: new Date('12/31/2006')
}).then(function (items) {
  // `items` contain the first 15 results
  // from the year 2006 in order
})

Resources