summaryrefslogtreecommitdiffstats
path: root/addon-sdk/source/lib/sdk/places
diff options
context:
space:
mode:
Diffstat (limited to 'addon-sdk/source/lib/sdk/places')
-rw-r--r--addon-sdk/source/lib/sdk/places/bookmarks.js395
-rw-r--r--addon-sdk/source/lib/sdk/places/contract.js73
-rw-r--r--addon-sdk/source/lib/sdk/places/events.js128
-rw-r--r--addon-sdk/source/lib/sdk/places/favicon.js49
-rw-r--r--addon-sdk/source/lib/sdk/places/history.js65
-rw-r--r--addon-sdk/source/lib/sdk/places/host/host-bookmarks.js238
-rw-r--r--addon-sdk/source/lib/sdk/places/host/host-query.js179
-rw-r--r--addon-sdk/source/lib/sdk/places/host/host-tags.js92
-rw-r--r--addon-sdk/source/lib/sdk/places/utils.js268
9 files changed, 0 insertions, 1487 deletions
diff --git a/addon-sdk/source/lib/sdk/places/bookmarks.js b/addon-sdk/source/lib/sdk/places/bookmarks.js
deleted file mode 100644
index c4f9528f1..000000000
--- a/addon-sdk/source/lib/sdk/places/bookmarks.js
+++ /dev/null
@@ -1,395 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-module.metadata = {
- "stability": "unstable",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-/*
- * Requiring hosts so they can subscribe to client messages
- */
-require('./host/host-bookmarks');
-require('./host/host-tags');
-require('./host/host-query');
-
-const { Cc, Ci } = require('chrome');
-const { Class } = require('../core/heritage');
-const { send } = require('../addon/events');
-const { defer, reject, all, resolve, promised } = require('../core/promise');
-const { EventTarget } = require('../event/target');
-const { emit } = require('../event/core');
-const { identity, defer:async } = require('../lang/functional');
-const { extend, merge } = require('../util/object');
-const { fromIterator } = require('../util/array');
-const {
- constructTree, fetchItem, createQuery,
- isRootGroup, createQueryOptions
-} = require('./utils');
-const {
- bookmarkContract, groupContract, separatorContract
-} = require('./contract');
-const bmsrv = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
- getService(Ci.nsINavBookmarksService);
-
-/*
- * Mapping of uncreated bookmarks with their created
- * counterparts
- */
-const itemMap = new WeakMap();
-
-/*
- * Constant used by nsIHistoryQuery; 1 is a bookmark query
- * https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryQueryOptions
- */
-const BOOKMARK_QUERY = 1;
-
-/*
- * Bookmark Item classes
- */
-
-const Bookmark = Class({
- extends: [
- bookmarkContract.properties(identity)
- ],
- initialize: function initialize (options) {
- merge(this, bookmarkContract(extend(defaults, options)));
- },
- type: 'bookmark',
- toString: () => '[object Bookmark]'
-});
-exports.Bookmark = Bookmark;
-
-const Group = Class({
- extends: [
- groupContract.properties(identity)
- ],
- initialize: function initialize (options) {
- // Don't validate if root group
- if (isRootGroup(options))
- merge(this, options);
- else
- merge(this, groupContract(extend(defaults, options)));
- },
- type: 'group',
- toString: () => '[object Group]'
-});
-exports.Group = Group;
-
-const Separator = Class({
- extends: [
- separatorContract.properties(identity)
- ],
- initialize: function initialize (options) {
- merge(this, separatorContract(extend(defaults, options)));
- },
- type: 'separator',
- toString: () => '[object Separator]'
-});
-exports.Separator = Separator;
-
-/*
- * Functions
- */
-
-function save (items, options) {
- items = [].concat(items);
- options = options || {};
- let emitter = EventTarget();
- let results = [];
- let errors = [];
- let root = constructTree(items);
- let cache = new Map();
-
- let isExplicitSave = item => !!~items.indexOf(item);
- // `walk` returns an aggregate promise indicating the completion
- // of the `commitItem` on each node, not whether or not that
- // commit was successful
-
- // Force this to be async, as if a ducktype fails validation,
- // the promise implementation will fire an error event, which will
- // not trigger the handler as it's not yet bound
- //
- // Can remove after `Promise.jsm` is implemented in Bug 881047,
- // which will guarantee next tick execution
- async(() => root.walk(preCommitItem).then(commitComplete))();
-
- function preCommitItem ({value:item}) {
- // Do nothing if tree root, default group (unsavable),
- // or if it's a dependency and not explicitly saved (in the list
- // of items to be saved), and not needed to be saved
- if (item === null || // node is the tree root
- isRootGroup(item) ||
- (getId(item) && !isExplicitSave(item)))
- return;
-
- return promised(validate)(item)
- .then(() => commitItem(item, options))
- .then(data => construct(data, cache))
- .then(savedItem => {
- // If item was just created, make a map between
- // the creation object and created object,
- // so we can reference the item that doesn't have an id
- if (!getId(item))
- saveId(item, savedItem.id);
-
- // Emit both the processed item, and original item
- // so a mapping can be understood in handler
- emit(emitter, 'data', savedItem, item);
-
- // Push to results iff item was explicitly saved
- if (isExplicitSave(item))
- results[items.indexOf(item)] = savedItem;
- }, reason => {
- // Force reason to be a string for consistency
- reason = reason + '';
- // Emit both the reason, and original item
- // so a mapping can be understood in handler
- emit(emitter, 'error', reason + '', item);
- // Store unsaved item in results list
- results[items.indexOf(item)] = item;
- errors.push(reason);
- });
- }
-
- // Called when traversal of the node tree is completed and all
- // items have been committed
- function commitComplete () {
- emit(emitter, 'end', results);
- }
-
- return emitter;
-}
-exports.save = save;
-
-function search (queries, options) {
- queries = [].concat(queries);
- let emitter = EventTarget();
- let cache = new Map();
- let queryObjs = queries.map(createQuery.bind(null, BOOKMARK_QUERY));
- let optionsObj = createQueryOptions(BOOKMARK_QUERY, options);
-
- // Can remove after `Promise.jsm` is implemented in Bug 881047,
- // which will guarantee next tick execution
- async(() => {
- send('sdk-places-query', { queries: queryObjs, options: optionsObj })
- .then(handleQueryResponse);
- })();
-
- function handleQueryResponse (data) {
- let deferreds = data.map(item => {
- return construct(item, cache).then(bookmark => {
- emit(emitter, 'data', bookmark);
- return bookmark;
- }, reason => {
- emit(emitter, 'error', reason);
- errors.push(reason);
- });
- });
-
- all(deferreds).then(data => {
- emit(emitter, 'end', data);
- }, () => emit(emitter, 'end', []));
- }
-
- return emitter;
-}
-exports.search = search;
-
-function remove (items) {
- return [].concat(items).map(item => {
- item.remove = true;
- return item;
- });
-}
-
-exports.remove = remove;
-
-/*
- * Internal Utilities
- */
-
-function commitItem (item, options) {
- // Get the item's ID, or getId it's saved version if it exists
- let id = getId(item);
- let data = normalize(item);
- let promise;
-
- data.id = id;
-
- if (!id) {
- promise = send('sdk-places-bookmarks-create', data);
- } else if (item.remove) {
- promise = send('sdk-places-bookmarks-remove', { id: id });
- } else {
- promise = send('sdk-places-bookmarks-last-updated', {
- id: id
- }).then(function (updated) {
- // If attempting to save an item that is not the
- // latest snapshot of a bookmark item, execute
- // the resolution function
- if (updated !== item.updated && options.resolve)
- return fetchItem(id)
- .then(options.resolve.bind(null, data));
- else
- return data;
- }).then(send.bind(null, 'sdk-places-bookmarks-save'));
- }
-
- return promise;
-}
-
-/*
- * Turns a bookmark item into a plain object,
- * converts `tags` from Set to Array, group instance to an id
- */
-function normalize (item) {
- let data = merge({}, item);
- // Circumvent prototype property of `type`
- delete data.type;
- data.type = item.type;
- data.tags = [];
- if (item.tags) {
- data.tags = fromIterator(item.tags);
- }
- data.group = getId(data.group) || exports.UNSORTED.id;
-
- return data;
-}
-
-/*
- * Takes a data object and constructs a BookmarkItem instance
- * of it, recursively generating parent instances as well.
- *
- * Pass in a `cache` Map to reuse instances of
- * bookmark items to reduce overhead;
- * The cache object is a map of id to a deferred with a
- * promise that resolves to the bookmark item.
- */
-function construct (object, cache, forced) {
- let item = instantiate(object);
- let deferred = defer();
-
- // Item could not be instantiated
- if (!item)
- return resolve(null);
-
- // Return promise for item if found in the cache,
- // and not `forced`. `forced` indicates that this is the construct
- // call that should not read from cache, but should actually perform
- // the construction, as it was set before several async calls
- if (cache.has(item.id) && !forced)
- return cache.get(item.id).promise;
- else if (cache.has(item.id))
- deferred = cache.get(item.id);
- else
- cache.set(item.id, deferred);
-
- // When parent group is found in cache, use
- // the same deferred value
- if (item.group && cache.has(item.group)) {
- cache.get(item.group).promise.then(group => {
- item.group = group;
- deferred.resolve(item);
- });
-
- // If not in the cache, and a root group, return
- // the premade instance
- } else if (rootGroups.get(item.group)) {
- item.group = rootGroups.get(item.group);
- deferred.resolve(item);
-
- // If not in the cache or a root group, fetch the parent
- } else {
- cache.set(item.group, defer());
- fetchItem(item.group).then(group => {
- return construct(group, cache, true);
- }).then(group => {
- item.group = group;
- deferred.resolve(item);
- }, deferred.reject);
- }
-
- return deferred.promise;
-}
-
-function instantiate (object) {
- if (object.type === 'bookmark')
- return Bookmark(object);
- if (object.type === 'group')
- return Group(object);
- if (object.type === 'separator')
- return Separator(object);
- return null;
-}
-
-/**
- * Validates a bookmark item; will throw an error if ininvalid,
- * to be used with `promised`. As bookmark items check on their class,
- * this only checks ducktypes
- */
-function validate (object) {
- if (!isDuckType(object)) return true;
- let contract = object.type === 'bookmark' ? bookmarkContract :
- object.type === 'group' ? groupContract :
- object.type === 'separator' ? separatorContract :
- null;
- if (!contract) {
- throw Error('No type specified');
- }
-
- // If object has a property set, and undefined,
- // manually override with default as it'll fail otherwise
- let withDefaults = Object.keys(defaults).reduce((obj, prop) => {
- if (obj[prop] == null) obj[prop] = defaults[prop];
- return obj;
- }, extend(object));
-
- contract(withDefaults);
-}
-
-function isDuckType (item) {
- return !(item instanceof Bookmark) &&
- !(item instanceof Group) &&
- !(item instanceof Separator);
-}
-
-function saveId (unsaved, id) {
- itemMap.set(unsaved, id);
-}
-
-// Fetches an item's ID from itself, or from the mapped items
-function getId (item) {
- return typeof item === 'number' ? item :
- item ? item.id || itemMap.get(item) :
- null;
-}
-
-/*
- * Set up the default, root groups
- */
-
-var defaultGroupMap = {
- MENU: bmsrv.bookmarksMenuFolder,
- TOOLBAR: bmsrv.toolbarFolder,
- UNSORTED: bmsrv.unfiledBookmarksFolder
-};
-
-var rootGroups = new Map();
-
-for (let i in defaultGroupMap) {
- let group = Object.freeze(Group({ title: i, id: defaultGroupMap[i] }));
- rootGroups.set(defaultGroupMap[i], group);
- exports[i] = group;
-}
-
-var defaults = {
- group: exports.UNSORTED,
- index: -1
-};
diff --git a/addon-sdk/source/lib/sdk/places/contract.js b/addon-sdk/source/lib/sdk/places/contract.js
deleted file mode 100644
index a3541c34d..000000000
--- a/addon-sdk/source/lib/sdk/places/contract.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-module.metadata = {
- "stability": "unstable"
-};
-
-const { Cc, Ci } = require('chrome');
-const { isValidURI, URL } = require('../url');
-const { contract } = require('../util/contract');
-const { extend } = require('../util/object');
-
-// map of property validations
-const validItem = {
- id: {
- is: ['number', 'undefined', 'null'],
- },
- group: {
- is: ['object', 'number', 'undefined', 'null'],
- ok: function (value) {
- return value &&
- (value.toString && value.toString() === '[object Group]') ||
- typeof value === 'number' ||
- value.type === 'group';
- },
- msg: 'The `group` property must be a valid Group object'
- },
- index: {
- is: ['undefined', 'null', 'number'],
- map: value => value == null ? -1 : value,
- msg: 'The `index` property must be a number.'
- },
- updated: {
- is: ['number', 'undefined']
- }
-};
-
-const validTitle = {
- title: {
- is: ['string'],
- msg: 'The `title` property must be defined.'
- }
-};
-
-const validURL = {
- url: {
- is: ['string'],
- ok: isValidURI,
- msg: 'The `url` property must be a valid URL.'
- }
-};
-
-const validTags = {
- tags: {
- is: ['object'],
- ok: tags => tags instanceof Set,
- map: function (tags) {
- if (Array.isArray(tags))
- return new Set(tags);
- if (tags == null)
- return new Set();
- return tags;
- },
- msg: 'The `tags` property must be a Set, or an array'
- }
-};
-
-exports.bookmarkContract = contract(
- extend(validItem, validTitle, validURL, validTags));
-exports.separatorContract = contract(validItem);
-exports.groupContract = contract(extend(validItem, validTitle));
diff --git a/addon-sdk/source/lib/sdk/places/events.js b/addon-sdk/source/lib/sdk/places/events.js
deleted file mode 100644
index a3f95ee03..000000000
--- a/addon-sdk/source/lib/sdk/places/events.js
+++ /dev/null
@@ -1,128 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-'use strict';
-
-module.metadata = {
- 'stability': 'experimental',
- 'engines': {
- 'Firefox': '*',
- "SeaMonkey": '*'
- }
-};
-
-const { Cc, Ci } = require('chrome');
-const { Unknown } = require('../platform/xpcom');
-const { Class } = require('../core/heritage');
-const { merge } = require('../util/object');
-const bookmarkService = Cc['@mozilla.org/browser/nav-bookmarks-service;1']
- .getService(Ci.nsINavBookmarksService);
-const historyService = Cc['@mozilla.org/browser/nav-history-service;1']
- .getService(Ci.nsINavHistoryService);
-const { mapBookmarkItemType } = require('./utils');
-const { EventTarget } = require('../event/target');
-const { emit } = require('../event/core');
-const { when } = require('../system/unload');
-
-const emitter = EventTarget();
-
-var HISTORY_ARGS = {
- onBeginUpdateBatch: [],
- onEndUpdateBatch: [],
- onClearHistory: [],
- onDeleteURI: ['url'],
- onDeleteVisits: ['url', 'visitTime'],
- onPageChanged: ['url', 'property', 'value'],
- onTitleChanged: ['url', 'title'],
- onVisit: [
- 'url', 'visitId', 'time', 'sessionId', 'referringId', 'transitionType'
- ]
-};
-
-var HISTORY_EVENTS = {
- onBeginUpdateBatch: 'history-start-batch',
- onEndUpdateBatch: 'history-end-batch',
- onClearHistory: 'history-start-clear',
- onDeleteURI: 'history-delete-url',
- onDeleteVisits: 'history-delete-visits',
- onPageChanged: 'history-page-changed',
- onTitleChanged: 'history-title-changed',
- onVisit: 'history-visit'
-};
-
-var BOOKMARK_ARGS = {
- onItemAdded: [
- 'id', 'parentId', 'index', 'type', 'url', 'title', 'dateAdded'
- ],
- onItemChanged: [
- 'id', 'property', null, 'value', 'lastModified', 'type', 'parentId'
- ],
- onItemMoved: [
- 'id', 'previousParentId', 'previousIndex', 'currentParentId',
- 'currentIndex', 'type'
- ],
- onItemRemoved: ['id', 'parentId', 'index', 'type', 'url'],
- onItemVisited: ['id', 'visitId', 'time', 'transitionType', 'url', 'parentId']
-};
-
-var BOOKMARK_EVENTS = {
- onItemAdded: 'bookmark-item-added',
- onItemChanged: 'bookmark-item-changed',
- onItemMoved: 'bookmark-item-moved',
- onItemRemoved: 'bookmark-item-removed',
- onItemVisited: 'bookmark-item-visited',
-};
-
-function createHandler (type, propNames) {
- propNames = propNames || [];
- return function (...args) {
- let data = propNames.reduce((acc, prop, i) => {
- if (prop)
- acc[prop] = formatValue(prop, args[i]);
- return acc;
- }, {});
-
- emit(emitter, 'data', {
- type: type,
- data: data
- });
- };
-}
-
-/*
- * Creates an observer, creating handlers based off of
- * the `events` names, and ordering arguments from `propNames` hash
- */
-function createObserverInstance (events, propNames) {
- let definition = Object.keys(events).reduce((prototype, eventName) => {
- prototype[eventName] = createHandler(events[eventName], propNames[eventName]);
- return prototype;
- }, {});
-
- return Class(merge(definition, { extends: Unknown }))();
-}
-
-/*
- * Formats `data` based off of the value of `type`
- */
-function formatValue (type, data) {
- if (type === 'type')
- return mapBookmarkItemType(data);
- if (type === 'url' && data)
- return data.spec;
- return data;
-}
-
-var historyObserver = createObserverInstance(HISTORY_EVENTS, HISTORY_ARGS);
-historyService.addObserver(historyObserver, false);
-
-var bookmarkObserver = createObserverInstance(BOOKMARK_EVENTS, BOOKMARK_ARGS);
-bookmarkService.addObserver(bookmarkObserver, false);
-
-when(() => {
- historyService.removeObserver(historyObserver);
- bookmarkService.removeObserver(bookmarkObserver);
-});
-
-exports.events = emitter;
diff --git a/addon-sdk/source/lib/sdk/places/favicon.js b/addon-sdk/source/lib/sdk/places/favicon.js
deleted file mode 100644
index 05b057db1..000000000
--- a/addon-sdk/source/lib/sdk/places/favicon.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-module.metadata = {
- "stability": "unstable",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-const { Cc, Ci, Cu } = require("chrome");
-const { defer, reject } = require("../core/promise");
-const FaviconService = Cc["@mozilla.org/browser/favicon-service;1"].
- getService(Ci.nsIFaviconService);
-const AsyncFavicons = FaviconService.QueryInterface(Ci.mozIAsyncFavicons);
-const { isValidURI } = require("../url");
-const { newURI, getURL } = require("../url/utils");
-
-/**
- * Takes an object of several possible types and
- * returns a promise that resolves to the page's favicon URI.
- * @param {String|Tab} object
- * @param {Function} (callback)
- * @returns {Promise}
- */
-
-function getFavicon (object, callback) {
- let url = getURL(object);
- let deferred = defer();
-
- if (url && isValidURI(url)) {
- AsyncFavicons.getFaviconURLForPage(newURI(url), function (aURI) {
- if (aURI && aURI.spec)
- deferred.resolve(aURI.spec.toString());
- else
- deferred.reject(null);
- });
- } else {
- deferred.reject(null);
- }
-
- if (callback) deferred.promise.then(callback, callback);
- return deferred.promise;
-}
-exports.getFavicon = getFavicon;
diff --git a/addon-sdk/source/lib/sdk/places/history.js b/addon-sdk/source/lib/sdk/places/history.js
deleted file mode 100644
index b243b024c..000000000
--- a/addon-sdk/source/lib/sdk/places/history.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-module.metadata = {
- "stability": "unstable",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-/*
- * Requiring hosts so they can subscribe to client messages
- */
-require('./host/host-bookmarks');
-require('./host/host-tags');
-require('./host/host-query');
-
-const { Cc, Ci } = require('chrome');
-const { Class } = require('../core/heritage');
-const { events, send } = require('../addon/events');
-const { defer, reject, all } = require('../core/promise');
-const { uuid } = require('../util/uuid');
-const { flatten } = require('../util/array');
-const { has, extend, merge, pick } = require('../util/object');
-const { emit } = require('../event/core');
-const { defer: async } = require('../lang/functional');
-const { EventTarget } = require('../event/target');
-const {
- urlQueryParser, createQuery, createQueryOptions
-} = require('./utils');
-
-/*
- * Constant used by nsIHistoryQuery; 0 is a history query
- * https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryQueryOptions
- */
-const HISTORY_QUERY = 0;
-
-var search = function query (queries, options) {
- queries = [].concat(queries);
- let emitter = EventTarget();
- let queryObjs = queries.map(createQuery.bind(null, HISTORY_QUERY));
- let optionsObj = createQueryOptions(HISTORY_QUERY, options);
-
- // Can remove after `Promise.jsm` is implemented in Bug 881047,
- // which will guarantee next tick execution
- async(() => {
- send('sdk-places-query', {
- query: queryObjs,
- options: optionsObj
- }).then(results => {
- results.map(item => emit(emitter, 'data', item));
- emit(emitter, 'end', results);
- }, reason => {
- emit(emitter, 'error', reason);
- emit(emitter, 'end', []);
- });
- })();
-
- return emitter;
-};
-exports.search = search;
diff --git a/addon-sdk/source/lib/sdk/places/host/host-bookmarks.js b/addon-sdk/source/lib/sdk/places/host/host-bookmarks.js
deleted file mode 100644
index 3245c4070..000000000
--- a/addon-sdk/source/lib/sdk/places/host/host-bookmarks.js
+++ /dev/null
@@ -1,238 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-module.metadata = {
- "stability": "experimental",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-const { Cc, Ci } = require('chrome');
-const browserHistory = Cc["@mozilla.org/browser/nav-history-service;1"].
- getService(Ci.nsIBrowserHistory);
-const asyncHistory = Cc["@mozilla.org/browser/history;1"].
- getService(Ci.mozIAsyncHistory);
-const bmsrv = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
- getService(Ci.nsINavBookmarksService);
-const taggingService = Cc["@mozilla.org/browser/tagging-service;1"].
- getService(Ci.nsITaggingService);
-const ios = Cc['@mozilla.org/network/io-service;1'].
- getService(Ci.nsIIOService);
-const { query } = require('./host-query');
-const {
- defer, all, resolve, promised, reject
-} = require('../../core/promise');
-const { request, response } = require('../../addon/host');
-const { send } = require('../../addon/events');
-const { on, emit } = require('../../event/core');
-const { filter } = require('../../event/utils');
-const { URL, isValidURI } = require('../../url');
-const { newURI } = require('../../url/utils');
-
-const DEFAULT_INDEX = bmsrv.DEFAULT_INDEX;
-const UNSORTED_ID = bmsrv.unfiledBookmarksFolder;
-const ROOT_FOLDERS = [
- bmsrv.unfiledBookmarksFolder, bmsrv.toolbarFolder,
- bmsrv.tagsFolder, bmsrv.bookmarksMenuFolder
-];
-
-const EVENT_MAP = {
- 'sdk-places-bookmarks-create': createBookmarkItem,
- 'sdk-places-bookmarks-save': saveBookmarkItem,
- 'sdk-places-bookmarks-last-updated': getBookmarkLastUpdated,
- 'sdk-places-bookmarks-get': getBookmarkItem,
- 'sdk-places-bookmarks-remove': removeBookmarkItem,
- 'sdk-places-bookmarks-get-all': getAllBookmarks,
- 'sdk-places-bookmarks-get-children': getChildren
-};
-
-function typeMap (type) {
- if (typeof type === 'number') {
- if (bmsrv.TYPE_BOOKMARK === type) return 'bookmark';
- if (bmsrv.TYPE_FOLDER === type) return 'group';
- if (bmsrv.TYPE_SEPARATOR === type) return 'separator';
- } else {
- if ('bookmark' === type) return bmsrv.TYPE_BOOKMARK;
- if ('group' === type) return bmsrv.TYPE_FOLDER;
- if ('separator' === type) return bmsrv.TYPE_SEPARATOR;
- }
-}
-
-function getBookmarkLastUpdated ({id}) {
- return resolve(bmsrv.getItemLastModified(id));
-}
-exports.getBookmarkLastUpdated;
-
-function createBookmarkItem (data) {
- let error;
-
- if (data.group == null) data.group = UNSORTED_ID;
- if (data.index == null) data.index = DEFAULT_INDEX;
-
- if (data.type === 'group')
- data.id = bmsrv.createFolder(
- data.group, data.title, data.index
- );
- else if (data.type === 'separator')
- data.id = bmsrv.insertSeparator(
- data.group, data.index
- );
- else
- data.id = bmsrv.insertBookmark(
- data.group, newURI(data.url), data.index, data.title
- );
-
- // In the event where default or no index is provided (-1),
- // query the actual index for the response
- if (data.index === -1)
- data.index = bmsrv.getItemIndex(data.id);
-
- try {
- data.updated = bmsrv.getItemLastModified(data.id);
- }
- catch (e) {
- console.exception(e);
- }
-
- return tag(data, true).then(() => data);
-}
-exports.createBookmarkItem = createBookmarkItem;
-
-function saveBookmarkItem (data) {
- let id = data.id;
- if (!id)
- reject('Item is missing id');
-
- let group = bmsrv.getFolderIdForItem(id);
- let index = bmsrv.getItemIndex(id);
- let type = bmsrv.getItemType(id);
- let title = typeMap(type) !== 'separator' ?
- bmsrv.getItemTitle(id) :
- undefined;
- let url = typeMap(type) === 'bookmark' ?
- bmsrv.getBookmarkURI(id).spec :
- undefined;
-
- if (url != data.url)
- bmsrv.changeBookmarkURI(id, newURI(data.url));
- else if (typeMap(type) === 'bookmark')
- data.url = url;
-
- if (title != data.title)
- bmsrv.setItemTitle(id, data.title);
- else if (typeMap(type) !== 'separator')
- data.title = title;
-
- if (data.group && data.group !== group)
- bmsrv.moveItem(id, data.group, data.index || -1);
- else if (data.index != null && data.index !== index) {
- // We use moveItem here instead of setItemIndex
- // so we don't have to manage the indicies of the siblings
- bmsrv.moveItem(id, group, data.index);
- } else if (data.index == null)
- data.index = index;
-
- data.updated = bmsrv.getItemLastModified(data.id);
-
- return tag(data).then(() => data);
-}
-exports.saveBookmarkItem = saveBookmarkItem;
-
-function removeBookmarkItem (data) {
- let id = data.id;
-
- if (!id)
- reject('Item is missing id');
-
- bmsrv.removeItem(id);
- return resolve(null);
-}
-exports.removeBookmarkItem = removeBookmarkItem;
-
-function getBookmarkItem (data) {
- let id = data.id;
-
- if (!id)
- reject('Item is missing id');
-
- let type = bmsrv.getItemType(id);
-
- data.type = typeMap(type);
-
- if (type === bmsrv.TYPE_BOOKMARK || type === bmsrv.TYPE_FOLDER)
- data.title = bmsrv.getItemTitle(id);
-
- if (type === bmsrv.TYPE_BOOKMARK) {
- data.url = bmsrv.getBookmarkURI(id).spec;
- // Should be moved into host-tags as a method
- data.tags = taggingService.getTagsForURI(newURI(data.url), {});
- }
-
- data.group = bmsrv.getFolderIdForItem(id);
- data.index = bmsrv.getItemIndex(id);
- data.updated = bmsrv.getItemLastModified(data.id);
-
- return resolve(data);
-}
-exports.getBookmarkItem = getBookmarkItem;
-
-function getAllBookmarks () {
- return query({}, { queryType: 1 }).then(bookmarks =>
- all(bookmarks.map(getBookmarkItem)));
-}
-exports.getAllBookmarks = getAllBookmarks;
-
-function getChildren ({ id }) {
- if (typeMap(bmsrv.getItemType(id)) !== 'group') return [];
- let ids = [];
- for (let i = 0; ids[ids.length - 1] !== -1; i++)
- ids.push(bmsrv.getIdForItemAt(id, i));
- ids.pop();
- return all(ids.map(id => getBookmarkItem({ id: id })));
-}
-exports.getChildren = getChildren;
-
-/*
- * Hook into host
- */
-
-var reqStream = filter(request, (data) => /sdk-places-bookmarks/.test(data.event));
-on(reqStream, 'data', ({ event, id, data }) => {
- if (!EVENT_MAP[event]) return;
-
- let resData = { id: id, event: event };
-
- promised(EVENT_MAP[event])(data).
- then(res => resData.data = res, e => resData.error = e).
- then(() => emit(response, 'data', resData));
-});
-
-function tag (data, isNew) {
- // If a new item, we can skip checking what other tags
- // are on the item
- if (data.type !== 'bookmark') {
- return resolve();
- }
- else if (!isNew) {
- return send('sdk-places-tags-get-tags-by-url', { url: data.url })
- .then(tags => {
- return send('sdk-places-tags-untag', {
- tags: tags.filter(tag => !~data.tags.indexOf(tag)),
- url: data.url
- });
- }).then(() => send('sdk-places-tags-tag', {
- url: data.url, tags: data.tags
- }));
- }
- else if (data.tags && data.tags.length) {
- return send('sdk-places-tags-tag', { url: data.url, tags: data.tags });
- }
- else
- return resolve();
-}
-
diff --git a/addon-sdk/source/lib/sdk/places/host/host-query.js b/addon-sdk/source/lib/sdk/places/host/host-query.js
deleted file mode 100644
index f2dbd6550..000000000
--- a/addon-sdk/source/lib/sdk/places/host/host-query.js
+++ /dev/null
@@ -1,179 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-module.metadata = {
- "stability": "experimental",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-const { Cc, Ci } = require('chrome');
-const { all } = require('../../core/promise');
-const { safeMerge, omit } = require('../../util/object');
-const historyService = Cc['@mozilla.org/browser/nav-history-service;1']
- .getService(Ci.nsINavHistoryService);
-const bookmarksService = Cc['@mozilla.org/browser/nav-bookmarks-service;1']
- .getService(Ci.nsINavBookmarksService);
-const { request, response } = require('../../addon/host');
-const { newURI } = require('../../url/utils');
-const { send } = require('../../addon/events');
-const { on, emit } = require('../../event/core');
-const { filter } = require('../../event/utils');
-
-const ROOT_FOLDERS = [
- bookmarksService.unfiledBookmarksFolder, bookmarksService.toolbarFolder,
- bookmarksService.bookmarksMenuFolder
-];
-
-const EVENT_MAP = {
- 'sdk-places-query': queryReceiver
-};
-
-// Properties that need to be manually
-// copied into a nsINavHistoryQuery object
-const MANUAL_QUERY_PROPERTIES = [
- 'uri', 'folder', 'tags', 'url', 'folder'
-];
-
-const PLACES_PROPERTIES = [
- 'uri', 'title', 'accessCount', 'time'
-];
-
-function execute (queries, options) {
- return new Promise(resolve => {
- let root = historyService
- .executeQueries(queries, queries.length, options).root;
- // Let's extract an eventual uri wildcard, if both domain and uri are set.
- // See utils.js::urlQueryParser() for more details.
- // In case of multiple queries, we only retain the first found wildcard.
- let uriWildcard = queries.reduce((prev, query) => {
- if (query.uri && query.domain) {
- if (!prev)
- prev = query.uri.spec;
- query.uri = null;
- }
- return prev;
- }, "");
- resolve(collect([], root, uriWildcard));
- });
-}
-
-function collect (acc, node, uriWildcard) {
- node.containerOpen = true;
- for (let i = 0; i < node.childCount; i++) {
- let child = node.getChild(i);
-
- if (!uriWildcard || child.uri.startsWith(uriWildcard)) {
- acc.push(child);
- }
- if (child.type === child.RESULT_TYPE_FOLDER) {
- let container = child.QueryInterface(Ci.nsINavHistoryContainerResultNode);
- collect(acc, container, uriWildcard);
- }
- }
- node.containerOpen = false;
- return acc;
-}
-
-function query (queries, options) {
- return new Promise((resolve, reject) => {
- queries = queries || [];
- options = options || {};
- let optionsObj, queryObjs;
-
- optionsObj = historyService.getNewQueryOptions();
- queryObjs = [].concat(queries).map(createQuery);
- if (!queryObjs.length) {
- queryObjs = [historyService.getNewQuery()];
- }
- safeMerge(optionsObj, options);
-
- /*
- * Currently `places:` queries are not supported
- */
- optionsObj.excludeQueries = true;
-
- execute(queryObjs, optionsObj).then((results) => {
- if (optionsObj.queryType === 0) {
- return results.map(normalize);
- }
- else if (optionsObj.queryType === 1) {
- // Formats query results into more standard
- // data structures for returning
- return all(results.map(({itemId}) =>
- send('sdk-places-bookmarks-get', { id: itemId })));
- }
- }).then(resolve, reject);
- });
-}
-exports.query = query;
-
-function createQuery (query) {
- query = query || {};
- let queryObj = historyService.getNewQuery();
-
- safeMerge(queryObj, omit(query, MANUAL_QUERY_PROPERTIES));
-
- if (query.tags && Array.isArray(query.tags))
- queryObj.tags = query.tags;
- if (query.uri || query.url)
- queryObj.uri = newURI(query.uri || query.url);
- if (query.folder)
- queryObj.setFolders([query.folder], 1);
- return queryObj;
-}
-
-function queryReceiver (message) {
- let queries = message.data.queries || message.data.query;
- let options = message.data.options;
- let resData = {
- id: message.id,
- event: message.event
- };
-
- query(queries, options).then(results => {
- resData.data = results;
- respond(resData);
- }, reason => {
- resData.error = reason;
- respond(resData);
- });
-}
-
-/*
- * Converts a nsINavHistoryResultNode into a plain object
- *
- * https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryResultNode
- */
-function normalize (historyObj) {
- return PLACES_PROPERTIES.reduce((obj, prop) => {
- if (prop === 'uri')
- obj.url = historyObj.uri;
- else if (prop === 'time') {
- // Cast from microseconds to milliseconds
- obj.time = Math.floor(historyObj.time / 1000)
- }
- else if (prop === 'accessCount')
- obj.visitCount = historyObj[prop];
- else
- obj[prop] = historyObj[prop];
- return obj;
- }, {});
-}
-
-/*
- * Hook into host
- */
-
-var reqStream = filter(request, data => /sdk-places-query/.test(data.event));
-on(reqStream, 'data', function (e) {
- if (EVENT_MAP[e.event]) EVENT_MAP[e.event](e);
-});
-
-function respond (data) {
- emit(response, 'data', data);
-}
diff --git a/addon-sdk/source/lib/sdk/places/host/host-tags.js b/addon-sdk/source/lib/sdk/places/host/host-tags.js
deleted file mode 100644
index 929a5d5af..000000000
--- a/addon-sdk/source/lib/sdk/places/host/host-tags.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-module.metadata = {
- "stability": "experimental",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-const { Cc, Ci } = require('chrome');
-const taggingService = Cc["@mozilla.org/browser/tagging-service;1"].
- getService(Ci.nsITaggingService);
-const ios = Cc['@mozilla.org/network/io-service;1'].
- getService(Ci.nsIIOService);
-const { URL } = require('../../url');
-const { newURI } = require('../../url/utils');
-const { request, response } = require('../../addon/host');
-const { on, emit } = require('../../event/core');
-const { filter } = require('../../event/utils');
-
-const EVENT_MAP = {
- 'sdk-places-tags-tag': tag,
- 'sdk-places-tags-untag': untag,
- 'sdk-places-tags-get-tags-by-url': getTagsByURL,
- 'sdk-places-tags-get-urls-by-tag': getURLsByTag
-};
-
-function tag (message) {
- let data = message.data;
- let resData = {
- id: message.id,
- event: message.event
- };
-
- resData.data = taggingService.tagURI(newURI(data.url), data.tags);
- respond(resData);
-}
-
-function untag (message) {
- let data = message.data;
- let resData = {
- id: message.id,
- event: message.event
- };
-
- resData.data = taggingService.untagURI(newURI(data.url), data.tags);
- respond(resData);
-}
-
-function getURLsByTag (message) {
- let data = message.data;
- let resData = {
- id: message.id,
- event: message.event
- };
-
- resData.data = taggingService
- .getURIsForTag(data.tag).map(uri => uri.spec);
- respond(resData);
-}
-
-function getTagsByURL (message) {
- let data = message.data;
- let resData = {
- id: message.id,
- event: message.event
- };
-
- resData.data = taggingService.getTagsForURI(newURI(data.url), {});
- respond(resData);
-}
-
-/*
- * Hook into host
- */
-
-var reqStream = filter(request, function (data) {
- return /sdk-places-tags/.test(data.event);
-});
-
-on(reqStream, 'data', function (e) {
- if (EVENT_MAP[e.event]) EVENT_MAP[e.event](e);
-});
-
-function respond (data) {
- emit(response, 'data', data);
-}
diff --git a/addon-sdk/source/lib/sdk/places/utils.js b/addon-sdk/source/lib/sdk/places/utils.js
deleted file mode 100644
index 44366d2aa..000000000
--- a/addon-sdk/source/lib/sdk/places/utils.js
+++ /dev/null
@@ -1,268 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-'use strict';
-
-module.metadata = {
- "stability": "experimental",
- "engines": {
- "Firefox": "*",
- "SeaMonkey": "*"
- }
-};
-
-const { Cc, Ci, Cu } = require('chrome');
-const { Class } = require('../core/heritage');
-const { method } = require('../lang/functional');
-const { defer, promised, all } = require('../core/promise');
-const { send } = require('../addon/events');
-const { EventTarget } = require('../event/target');
-const { merge } = require('../util/object');
-const bmsrv = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
- getService(Ci.nsINavBookmarksService);
-
-Cu.importGlobalProperties(["URL"]);
-
-/*
- * TreeNodes are used to construct dependency trees
- * for BookmarkItems
- */
-var TreeNode = Class({
- initialize: function (value) {
- this.value = value;
- this.children = [];
- },
- add: function (values) {
- [].concat(values).forEach(value => {
- this.children.push(value instanceof TreeNode ? value : TreeNode(value));
- });
- },
- get length () {
- let count = 0;
- this.walk(() => count++);
- // Do not count the current node
- return --count;
- },
- get: method(get),
- walk: method(walk),
- toString: () => '[object TreeNode]'
-});
-exports.TreeNode = TreeNode;
-
-/*
- * Descends down from `node` applying `fn` to each in order.
- * `fn` can return values or promises -- if promise returned,
- * children are not processed until resolved. `fn` is passed
- * one argument, the current node, `curr`.
- */
-function walk (curr, fn) {
- return promised(fn)(curr).then(val => {
- return all(curr.children.map(child => walk(child, fn)));
- });
-}
-
-/*
- * Descends from the TreeNode `node`, returning
- * the node with value `value` if found or `null`
- * otherwise
- */
-function get (node, value) {
- if (node.value === value) return node;
- for (let child of node.children) {
- let found = get(child, value);
- if (found) return found;
- }
- return null;
-}
-
-/*
- * Constructs a tree of bookmark nodes
- * returning the root (value: null);
- */
-
-function constructTree (items) {
- let root = TreeNode(null);
- items.forEach(treeify.bind(null, root));
-
- function treeify (root, item) {
- // If node already exists, skip
- let node = root.get(item);
- if (node) return node;
- node = TreeNode(item);
-
- let parentNode = item.group ? treeify(root, item.group) : root;
- parentNode.add(node);
-
- return node;
- }
-
- return root;
-}
-exports.constructTree = constructTree;
-
-/*
- * Shortcut for converting an id, or an object with an id, into
- * an object with corresponding bookmark data
- */
-function fetchItem (item) {
- return send('sdk-places-bookmarks-get', { id: item.id || item });
-}
-exports.fetchItem = fetchItem;
-
-/*
- * Takes an ID or an object with ID and checks it against
- * the root bookmark folders
- */
-function isRootGroup (id) {
- id = id && id.id;
- return ~[bmsrv.bookmarksMenuFolder, bmsrv.toolbarFolder,
- bmsrv.unfiledBookmarksFolder
- ].indexOf(id);
-}
-exports.isRootGroup = isRootGroup;
-
-/*
- * Merges appropriate options into query based off of url
- * 4 scenarios:
- *
- * 'moz.com' // domain: moz.com, domainIsHost: true
- * --> 'http://moz.com', 'http://moz.com/thunderbird'
- * '*.moz.com' // domain: moz.com, domainIsHost: false
- * --> 'http://moz.com', 'http://moz.com/index', 'http://ff.moz.com/test'
- * 'http://moz.com' // uri: http://moz.com/
- * --> 'http://moz.com/'
- * 'http://moz.com/*' // uri: http://moz.com/, domain: moz.com, domainIsHost: true
- * --> 'http://moz.com/', 'http://moz.com/thunderbird'
- */
-
-function urlQueryParser (query, url) {
- if (!url) return;
- if (/^https?:\/\//.test(url)) {
- query.uri = url.charAt(url.length - 1) === '/' ? url : url + '/';
- if (/\*$/.test(url)) {
- // Wildcard searches on URIs are not supported, so try to extract a
- // domain and filter the data later.
- url = url.replace(/\*$/, '');
- try {
- query.domain = new URL(url).hostname;
- query.domainIsHost = true;
- // Unfortunately here we cannot use an expando to store the wildcard,
- // cause the query is a wrapped native XPCOM object, so we reuse uri.
- // We clearly don't want to query for both uri and domain, thus we'll
- // have to handle this in host-query.js::execute()
- query.uri = url;
- } catch (ex) {
- // Cannot extract an host cause it's not a valid uri, the query will
- // just return nothing.
- }
- }
- } else {
- if (/^\*/.test(url)) {
- query.domain = url.replace(/^\*\./, '');
- query.domainIsHost = false;
- } else {
- query.domain = url;
- query.domainIsHost = true;
- }
- }
-}
-exports.urlQueryParser = urlQueryParser;
-
-/*
- * Takes an EventEmitter and returns a promise that
- * aggregates results and handles a bulk resolve and reject
- */
-
-function promisedEmitter (emitter) {
- let { promise, resolve, reject } = defer();
- let errors = [];
- emitter.on('error', error => errors.push(error));
- emitter.on('end', (items) => {
- if (errors.length) reject(errors[0]);
- else resolve(items);
- });
- return promise;
-}
-exports.promisedEmitter = promisedEmitter;
-
-
-// https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryQueryOptions
-function createQuery (type, query) {
- query = query || {};
- let qObj = {
- searchTerms: query.query
- };
-
- urlQueryParser(qObj, query.url);
-
- // 0 === history
- if (type === 0) {
- // PRTime used by query is in microseconds, not milliseconds
- qObj.beginTime = (query.from || 0) * 1000;
- qObj.endTime = (query.to || new Date()) * 1000;
-
- // Set reference time to Epoch
- qObj.beginTimeReference = 0;
- qObj.endTimeReference = 0;
- }
- // 1 === bookmarks
- else if (type === 1) {
- qObj.tags = query.tags;
- qObj.folder = query.group && query.group.id;
- }
- // 2 === unified (not implemented on platform)
- else if (type === 2) {
-
- }
-
- return qObj;
-}
-exports.createQuery = createQuery;
-
-// https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryQueryOptions
-
-const SORT_MAP = {
- title: 1,
- date: 3, // sort by visit date
- url: 5,
- visitCount: 7,
- // keywords currently unsupported
- // keyword: 9,
- dateAdded: 11, // bookmarks only
- lastModified: 13 // bookmarks only
-};
-
-function createQueryOptions (type, options) {
- options = options || {};
- let oObj = {};
- oObj.sortingMode = SORT_MAP[options.sort] || 0;
- if (options.descending && options.sort)
- oObj.sortingMode++;
-
- // Resolve to default sort if ineligible based on query type
- if (type === 0 && // history
- (options.sort === 'dateAdded' || options.sort === 'lastModified'))
- oObj.sortingMode = 0;
-
- oObj.maxResults = typeof options.count === 'number' ? options.count : 0;
-
- oObj.queryType = type;
-
- return oObj;
-}
-exports.createQueryOptions = createQueryOptions;
-
-
-function mapBookmarkItemType (type) {
- if (typeof type === 'number') {
- if (bmsrv.TYPE_BOOKMARK === type) return 'bookmark';
- if (bmsrv.TYPE_FOLDER === type) return 'group';
- if (bmsrv.TYPE_SEPARATOR === type) return 'separator';
- } else {
- if ('bookmark' === type) return bmsrv.TYPE_BOOKMARK;
- if ('group' === type) return bmsrv.TYPE_FOLDER;
- if ('separator' === type) return bmsrv.TYPE_SEPARATOR;
- }
-}
-exports.mapBookmarkItemType = mapBookmarkItemType;