addon-sdk/source/lib/sdk/places/utils.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 'use strict';
     7 module.metadata = {
     8   "stability": "experimental",
     9   "engines": {
    10     "Firefox": "*"
    11   }
    12 };
    14 const { Cc, Ci } = require('chrome');
    15 const { Class } = require('../core/heritage');
    16 const { method } = require('../lang/functional');
    17 const { defer, promised, all } = require('../core/promise');
    18 const { send } = require('../addon/events');
    19 const { EventTarget } = require('../event/target');
    20 const { merge } = require('../util/object');
    21 const bmsrv = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
    22                 getService(Ci.nsINavBookmarksService);
    24 /*
    25  * TreeNodes are used to construct dependency trees
    26  * for BookmarkItems
    27  */
    28 let TreeNode = Class({
    29   initialize: function (value) {
    30     this.value = value;
    31     this.children = [];
    32   },
    33   add: function (values) {
    34     [].concat(values).forEach(value => {
    35       this.children.push(value instanceof TreeNode ? value : TreeNode(value));
    36     });
    37   },
    38   get length () {
    39     let count = 0;
    40     this.walk(() => count++);
    41     // Do not count the current node
    42     return --count;
    43   },
    44   get: method(get),
    45   walk: method(walk),
    46   toString: function () '[object TreeNode]'
    47 });
    48 exports.TreeNode = TreeNode;
    50 /*
    51  * Descends down from `node` applying `fn` to each in order.
    52  * `fn` can return values or promises -- if promise returned,
    53  * children are not processed until resolved. `fn` is passed 
    54  * one argument, the current node, `curr`.
    55  */
    56 function walk (curr, fn) {
    57   return promised(fn)(curr).then(val => {
    58     return all(curr.children.map(child => walk(child, fn)));
    59   });
    60 } 
    62 /*
    63  * Descends from the TreeNode `node`, returning
    64  * the node with value `value` if found or `null`
    65  * otherwise
    66  */
    67 function get (node, value) {
    68   if (node.value === value) return node;
    69   for (let child of node.children) {
    70     let found = get(child, value);
    71     if (found) return found;
    72   }
    73   return null;
    74 }
    76 /*
    77  * Constructs a tree of bookmark nodes
    78  * returning the root (value: null);
    79  */
    81 function constructTree (items) {
    82   let root = TreeNode(null);
    83   items.forEach(treeify.bind(null, root));
    85   function treeify (root, item) {
    86     // If node already exists, skip
    87     let node = root.get(item);
    88     if (node) return node;
    89     node = TreeNode(item);
    91     let parentNode = item.group ? treeify(root, item.group) : root;
    92     parentNode.add(node);
    94     return node;
    95   }
    97   return root;
    98 }
    99 exports.constructTree = constructTree;
   101 /*
   102  * Shortcut for converting an id, or an object with an id, into
   103  * an object with corresponding bookmark data
   104  */
   105 function fetchItem (item)
   106   send('sdk-places-bookmarks-get', { id: item.id || item })
   107 exports.fetchItem = fetchItem;
   109 /*
   110  * Takes an ID or an object with ID and checks it against
   111  * the root bookmark folders
   112  */
   113 function isRootGroup (id) {
   114   id = id && id.id;
   115   return ~[bmsrv.bookmarksMenuFolder, bmsrv.toolbarFolder,
   116     bmsrv.unfiledBookmarksFolder
   117   ].indexOf(id);
   118 }
   119 exports.isRootGroup = isRootGroup;
   121 /*
   122  * Merges appropriate options into query based off of url
   123  * 4 scenarios:
   124  * 
   125  * 'moz.com' // domain: moz.com, domainIsHost: true
   126  *    --> 'http://moz.com', 'http://moz.com/thunderbird'
   127  * '*.moz.com' // domain: moz.com, domainIsHost: false
   128  *    --> 'http://moz.com', 'http://moz.com/index', 'http://ff.moz.com/test'
   129  * 'http://moz.com' // url: http://moz.com/, urlIsPrefix: false
   130  *    --> 'http://moz.com/'
   131  * 'http://moz.com/*' // url: http://moz.com/, urlIsPrefix: true
   132  *    --> 'http://moz.com/', 'http://moz.com/thunderbird'
   133  */
   135 function urlQueryParser (query, url) {
   136   if (!url) return;
   137   if (/^https?:\/\//.test(url)) {
   138     query.uri = url.charAt(url.length - 1) === '/' ? url : url + '/';
   139     if (/\*$/.test(url)) {
   140       query.uri = url.replace(/\*$/, '');
   141       query.uriIsPrefix = true;
   142     }
   143   } else {
   144     if (/^\*/.test(url)) {
   145       query.domain = url.replace(/^\*\./, '');
   146       query.domainIsHost = false;
   147     } else {
   148       query.domain = url;
   149       query.domainIsHost = true;
   150     }
   151   }
   152 }
   153 exports.urlQueryParser = urlQueryParser;
   155 /*
   156  * Takes an EventEmitter and returns a promise that
   157  * aggregates results and handles a bulk resolve and reject
   158  */
   160 function promisedEmitter (emitter) {
   161   let { promise, resolve, reject } = defer();
   162   let errors = [];
   163   emitter.on('error', error => errors.push(error));
   164   emitter.on('end', (items) => {
   165     if (errors.length) reject(errors[0]);
   166     else resolve(items);
   167   });
   168   return promise;
   169 }
   170 exports.promisedEmitter = promisedEmitter;
   173 // https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryQueryOptions
   174 function createQuery (type, query) {
   175   query = query || {};
   176   let qObj = {
   177     searchTerms: query.query
   178   };
   180   urlQueryParser(qObj, query.url);
   182   // 0 === history
   183   if (type === 0) {
   184     // PRTime used by query is in microseconds, not milliseconds
   185     qObj.beginTime = (query.from || 0) * 1000;
   186     qObj.endTime = (query.to || new Date()) * 1000;
   188     // Set reference time to Epoch
   189     qObj.beginTimeReference = 0;
   190     qObj.endTimeReference = 0;
   191   }
   192   // 1 === bookmarks
   193   else if (type === 1) {
   194     qObj.tags = query.tags;
   195     qObj.folder = query.group && query.group.id;
   196   } 
   197   // 2 === unified (not implemented on platform)
   198   else if (type === 2) {
   200   }
   202   return qObj;
   203 }
   204 exports.createQuery = createQuery;
   206 // https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryQueryOptions
   208 const SORT_MAP = {
   209   title: 1,
   210   date: 3, // sort by visit date
   211   url: 5,
   212   visitCount: 7,
   213   // keywords currently unsupported
   214   // keyword: 9,
   215   dateAdded: 11, // bookmarks only
   216   lastModified: 13 // bookmarks only
   217 };
   219 function createQueryOptions (type, options) {
   220   options = options || {};
   221   let oObj = {};
   222   oObj.sortingMode = SORT_MAP[options.sort] || 0;
   223   if (options.descending && options.sort)
   224     oObj.sortingMode++;
   226   // Resolve to default sort if ineligible based on query type
   227   if (type === 0 && // history
   228       (options.sort === 'dateAdded' || options.sort === 'lastModified'))
   229     oObj.sortingMode = 0;
   231   oObj.maxResults = typeof options.count === 'number' ? options.count : 0;
   233   oObj.queryType = type;
   235   return oObj;
   236 }
   237 exports.createQueryOptions = createQueryOptions;
   240 function mapBookmarkItemType (type) {
   241   if (typeof type === 'number') {
   242     if (bmsrv.TYPE_BOOKMARK === type) return 'bookmark';
   243     if (bmsrv.TYPE_FOLDER === type) return 'group';
   244     if (bmsrv.TYPE_SEPARATOR === type) return 'separator';
   245   } else {
   246     if ('bookmark' === type) return bmsrv.TYPE_BOOKMARK;
   247     if ('group' === type) return bmsrv.TYPE_FOLDER;
   248     if ('separator' === type) return bmsrv.TYPE_SEPARATOR;
   249   }
   250 }
   251 exports.mapBookmarkItemType = mapBookmarkItemType;

mercurial