]> git.donarmstrong.com Git - dactyl.git/blobdiff - common/modules/bookmarkcache.jsm
Import r6976 from upstream hg supporting Firefox up to 25.*
[dactyl.git] / common / modules / bookmarkcache.jsm
index e85a7c6c978b4c415bd847f788eaf6365692b37f..031618941e915c2e2d6121f7cad5344085be185a 100644 (file)
@@ -1,14 +1,24 @@
-// Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
+// Copyright ©2008-2013 Kris Maglione <maglione.k at Gmail>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
 "use strict";
 
-Components.utils.import("resource://dactyl/bootstrap.jsm");
 defineModule("bookmarkcache", {
     exports: ["Bookmark", "BookmarkCache", "Keyword", "bookmarkcache"],
-    require: ["services", "storage", "util"]
-}, this);
+    require: ["services", "util"]
+});
+
+this.lazyRequire("storage", ["storage"]);
+
+function newURI(url, charset, base) {
+    try {
+        return services.io.newURI(url, charset, base);
+    }
+    catch (e) {
+        throw Error(e);
+    }
+}
 
 var Bookmark = Struct("url", "title", "icon", "post", "keyword", "tags", "charset", "id");
 var Keyword = Struct("keyword", "title", "icon", "url");
@@ -17,26 +27,38 @@ update(Bookmark.prototype, {
     get extra() [
         ["keyword", this.keyword,         "Keyword"],
         ["tags",    this.tags.join(", "), "Tag"]
-    ].filter(function (item) item[1]),
+    ].filter(item => item[1]),
 
-    get uri() util.newURI(this.url),
+    get uri() newURI(this.url),
+    set uri(uri) {
+        let tags = this.tags;
+        this.tags = null;
+        services.bookmarks.changeBookmarkURI(this.id, uri);
+        this.tags = tags;
+    },
 
     encodeURIComponent: function _encodeURIComponent(str) {
         if (!this.charset || this.charset === "UTF-8")
             return encodeURIComponent(str);
         let conv = services.CharsetConv(this.charset);
-        return escape(conv.ConvertFromUnicode(str) + conv.Finish());
+        return escape(conv.ConvertFromUnicode(str) + conv.Finish()).replace(/\+/g, encodeURIComponent);
+    },
+
+    get folder() {
+        let res = [];
+        res.toString = function () this.join("/");
+
+        let id = this.id, parent, title;
+        while ((id    = services.bookmarks.getFolderIdForItem(id)) &&
+               (title = services.bookmarks.getItemTitle(id)))
+            res.push(title);
+
+        return res.reverse();
     }
 })
+Bookmark.prototype.members.uri = Bookmark.prototype.members.url;
 Bookmark.setter = function (key, func) this.prototype.__defineSetter__(key, func);
-Bookmark.setter("url", function (val) {
-    if (isString(val))
-        val = util.newURI(val);
-    let tags = this.tags;
-    this.tags = null;
-    services.bookmarks.changeBookmarkURI(this.id, val);
-    this.tags = tags;
-});
+Bookmark.setter("url", function (val) { this.uri = isString(val) ? newURI(val) : val; });
 Bookmark.setter("title", function (val) { services.bookmarks.setItemTitle(this.id, val); });
 Bookmark.setter("post", function (val) { bookmarkcache.annotate(this.id, bookmarkcache.POST, val); });
 Bookmark.setter("charset", function (val) { bookmarkcache.annotate(this.id, bookmarkcache.CHARSET, val); });
@@ -63,12 +85,12 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), {
 
     __iterator__: function () (val for ([, val] in Iterator(bookmarkcache.bookmarks))),
 
-    get bookmarks() Class.replaceProperty(this, "bookmarks", this.load()),
+    bookmarks: Class.Memoize(function () this.load()),
 
-    keywords: Class.memoize(function () array.toObject([[b.keyword, b] for (b in this) if (b.keyword)])),
+    keywords: Class.Memoize(function () array.toObject([[b.keyword, b] for (b in this) if (b.keyword)])),
 
     rootFolders: ["toolbarFolder", "bookmarksMenuFolder", "unfiledBookmarksFolder"]
-        .map(function (s) services.bookmarks[s]),
+        .map(s => services.bookmarks[s]),
 
     _deleteBookmark: function deleteBookmark(id) {
         let result = this.bookmarks[id] || null;
@@ -79,9 +101,13 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), {
     _loadBookmark: function loadBookmark(node) {
         if (node.uri == null) // How does this happen?
             return false;
-        let uri = util.newURI(node.uri);
+
+        let uri = newURI(node.uri);
         let keyword = services.bookmarks.getKeywordForBookmark(node.itemId);
-        let tags = services.tagging.getTagsForURI(uri, {}) || [];
+
+        let tags = "tags" in node ? (node.tags ? node.tags.split(/, /g) : [])
+                                  : services.tagging.getTagsForURI(uri, {}) || [];
+
         let post = BookmarkCache.getAnnotation(node.itemId, this.POST);
         let charset = BookmarkCache.getAnnotation(node.itemId, this.CHARSET);
         return Bookmark(node.uri, node.title, node.icon && node.icon.spec, post, keyword, tags, charset, node.itemId);
@@ -96,7 +122,7 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), {
     },
 
     get: function (url) {
-        let ids = services.bookmarks.getBookmarkIdsForURI(util.newURI(url), {});
+        let ids = services.bookmarks.getBookmarkIdsForURI(newURI(url), {});
         for (let id in values(ids))
             if (id in this.bookmarks)
                 return this.bookmarks[id];
@@ -129,7 +155,7 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), {
      */
     isBookmarked: function isBookmarked(uri) {
         if (isString(uri))
-            uri = util.newURI(uri);
+            uri = newURI(uri);
 
         try {
             return services.bookmarks
@@ -154,27 +180,27 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), {
     load: function load() {
         let bookmarks = {};
 
-        let folders = this.rootFolders.slice();
         let query = services.history.getNewQuery();
         let options = services.history.getNewQueryOptions();
-        while (folders.length > 0) {
-            query.setFolders(folders, 1);
-            folders.shift();
-            let result = services.history.executeQuery(query, options);
-            let folder = result.root;
-            folder.containerOpen = true;
+        options.queryType = options.QUERY_TYPE_BOOKMARKS;
+        try {
+            // https://bugzil.la/702639
+            options.excludeItemIfParentHasAnnotation = "livemark/feedURI";
+        }
+        catch (e) {}
 
+        let { root } = services.history.executeQuery(query, options);
+        root.containerOpen = true;
+        try {
             // iterate over the immediate children of this folder
-            for (let i = 0; i < folder.childCount; i++) {
-                let node = folder.getChild(i);
-                if (node.type == node.RESULT_TYPE_FOLDER)   // folder
-                    folders.push(node.itemId);
-                else if (node.type == node.RESULT_TYPE_URI) // bookmark
+            for (let i = 0; i < root.childCount; i++) {
+                let node = root.getChild(i);
+                if (node.type == node.RESULT_TYPE_URI) // bookmark
                     bookmarks[node.itemId] = this._loadBookmark(node);
             }
-
-            // close a container after using it!
-            folder.containerOpen = false;
+        }
+        finally {
+            root.containerOpen = false;
         }
 
         return bookmarks;
@@ -218,12 +244,15 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), {
         }
     }
 }, {
+    DEFAULT_FAVICON: "chrome://mozapps/skin/places/defaultFavicon.png",
+
     getAnnotation: function getAnnotation(item, anno)
         services.annotation.itemHasAnnotation(item, anno) ?
         services.annotation.getItemAnnotation(item, anno) : null,
+
     getFavicon: function getFavicon(uri) {
         try {
-            return services.favicon.getFaviconImageForPage(util.newURI(uri)).spec;
+            return services.favicon.getFaviconImageForPage(newURI(uri)).spec;
         }
         catch (e) {
             return "";
@@ -233,4 +262,4 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), {
 
 endModule();
 
-// vim: set fdm=marker sw=4 sts=4 et ft=javascript:
+// vim: set fdm=marker sw=4 sts=4 ts=8 et ft=javascript: