]> git.donarmstrong.com Git - dactyl.git/blobdiff - common/content/bookmarks.js
Import 1.0rc1 supporting Firefox up to 11.*
[dactyl.git] / common / content / bookmarks.js
index 1ce6ee11a1bd2ff156ade600f6e8230e218dbcdf..ca1bdb001d9b3743cf1d2478b7588d20b60e407a 100644 (file)
@@ -4,9 +4,7 @@
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-"use strict";
-
-var DEFAULT_FAVICON = "chrome://mozapps/skin/places/defaultFavicon.png";
+/* use strict */
 
 // also includes methods for dealing with keywords and search engines
 var Bookmarks = Module("bookmarks", {
@@ -38,7 +36,7 @@ var Bookmarks = Module("bookmarks", {
     get format() ({
         anchored: false,
         title: ["URL", "Info"],
-        keys: { text: "url", description: "title", icon: "icon", extra: "extra", tags: "tags" },
+        keys: { text: "url", description: "title", icon: "icon", extra: "extra", tags: "tags", isURI: function () true },
         process: [template.icon, template.bookmarkDescription]
     }),
 
@@ -63,49 +61,54 @@ var Bookmarks = Module("bookmarks", {
      *      Otherwise, if a bookmark for the given URL exists it is
      *      updated instead.
      *      @optional
-     * @returns {boolean} True if the bookmark was added or updated
-     *      successfully.
+     * @returns {boolean} True if the bookmark was updated, false if a
+     *      new bookmark was added.
      */
     add: function add(unfiled, title, url, keyword, tags, force) {
         // FIXME
         if (isObject(unfiled))
-            var { unfiled, title, url, keyword, tags, post, charset, force } = unfiled;
-
-        try {
-            let uri = util.createURI(url);
-            if (!force && bookmarkcache.isBookmarked(uri))
-                for (var bmark in bookmarkcache)
-                    if (bmark.url == uri.spec) {
-                        if (title)
-                            bmark.title = title;
+            var { id, unfiled, title, url, keyword, tags, post, charset, force } = unfiled;
+
+        let uri = util.createURI(url);
+        if (id != null)
+            var bmark = bookmarkcache.bookmarks[id];
+        else if (!force) {
+            if (keyword && Set.has(bookmarkcache.keywords, keyword))
+                bmark = bookmarkcache.keywords[keyword];
+            else if (bookmarkcache.isBookmarked(uri))
+                for (bmark in bookmarkcache)
+                    if (bmark.url == uri.spec)
                         break;
-                    }
+        }
 
-            if (tags) {
-                PlacesUtils.tagging.untagURI(uri, null);
-                PlacesUtils.tagging.tagURI(uri, tags);
-            }
-            if (bmark == undefined)
-                bmark = bookmarkcache.bookmarks[
-                    services.bookmarks.insertBookmark(
-                         services.bookmarks[unfiled ? "unfiledBookmarksFolder" : "bookmarksMenuFolder"],
-                         uri, -1, title || url)];
-            if (!bmark)
-                return false;
-
-            if (charset !== undefined)
-                bmark.charset = charset;
-            if (post !== undefined)
-                bmark.post = post;
-            if (keyword)
-                bmark.keyword = keyword;
+        if (tags) {
+            PlacesUtils.tagging.untagURI(uri, null);
+            PlacesUtils.tagging.tagURI(uri, tags);
         }
-        catch (e) {
-            util.reportError(e);
-            return false;
+
+        let updated = !!bmark;
+        if (bmark == undefined)
+            bmark = bookmarkcache.bookmarks[
+                services.bookmarks.insertBookmark(
+                     services.bookmarks[unfiled ? "unfiledBookmarksFolder" : "bookmarksMenuFolder"],
+                     uri, -1, title || url)];
+        else {
+            if (title)
+                bmark.title = title;
+            if (!uri.equals(bmark.uri))
+                bmark.uri = uri;
         }
 
-        return true;
+        util.assert(bmark);
+
+        if (charset !== undefined)
+            bmark.charset = charset;
+        if (post !== undefined)
+            bmark.post = post;
+        if (keyword)
+            bmark.keyword = keyword;
+
+        return updated;
     },
 
     /**
@@ -116,13 +119,13 @@ var Bookmarks = Module("bookmarks", {
      */
     addSearchKeyword: function addSearchKeyword(elem) {
         if (elem instanceof HTMLFormElement || elem.form)
-            var [url, post, charset] = util.parseForm(elem);
+            var { url, postData, charset } = DOM(elem).formData;
         else
-            var [url, post, charset] = [elem.href || elem.src, null, elem.ownerDocument.characterSet];
+            var [url, postData, charset] = [elem.href || elem.src, null, elem.ownerDocument.characterSet];
 
         let options = { "-title": "Search " + elem.ownerDocument.title };
-        if (post != null)
-            options["-post"] = post;
+        if (postData != null)
+            options["-post"] = postData;
         if (charset != null && charset !== "UTF-8")
             options["-charset"] = charset;
 
@@ -163,6 +166,7 @@ var Bookmarks = Module("bookmarks", {
             let extra = "";
             if (title != url)
                 extra = " (" + title + ")";
+
             this.add({ unfiled: true, title: title, url: url });
             dactyl.echomsg({ domains: [util.getHost(url)], message: _("bookmark.added", url + extra) });
         }
@@ -247,29 +251,49 @@ var Bookmarks = Module("bookmarks", {
     getSuggestions: function getSuggestions(engineName, query, callback) {
         const responseType = "application/x-suggestions+json";
 
+        if (Set.has(this.suggestionProviders, engineName))
+            return this.suggestionProviders[engineName](query, callback);
+
         let engine = Set.has(this.searchEngines, engineName) && this.searchEngines[engineName];
         if (engine && engine.supportsResponseType(responseType))
             var queryURI = engine.getSubmission(query, responseType).uri.spec;
         if (!queryURI)
             return (callback || util.identity)([]);
 
+        function parse(req) JSON.parse(req.responseText)[1].filter(isString);
+        return this.makeSuggestions(queryURI, parse, callback);
+    },
+
+    /**
+     * Given a query URL, response parser, and optionally a callback,
+     * fetch and parse search query results for {@link getSuggestions}.
+     *
+     * @param {string} url The URL to fetch.
+     * @param {function(XMLHttpRequest):[string]} parser The function which
+     *      parses the response.
+     */
+    makeSuggestions: function makeSuggestions(url, parser, callback) {
         function process(req) {
             let results = [];
             try {
-                results = JSON.parse(req.responseText)[1].filter(isString);
+                results = parser(req);
+            }
+            catch (e) {
+                util.reportError(e);
             }
-            catch (e) {}
             if (callback)
                 return callback(results);
             return results;
         }
 
-        let req = util.httpGet(queryURI, callback && process);
+        let req = util.httpGet(url, callback && process);
         if (callback)
             return req;
         return process(req);
     },
 
+    suggestionProviders: {},
+
     /**
      * Returns an array containing a search URL and POST data for the
      * given search string. If *useDefsearch* is true, the string is
@@ -378,14 +402,6 @@ var Bookmarks = Module("bookmarks", {
 }, {
 }, {
     commands: function () {
-        commands.add(["ju[mps]"],
-            "Show jumplist",
-            function () {
-                let sh = history.session;
-                commandline.commandOutput(template.jumps(sh.index, sh));
-            },
-            { argCount: "0" });
-
         // TODO: Clean this up.
         const tags = {
             names: ["-tags", "-T"],
@@ -432,15 +448,19 @@ var Bookmarks = Module("bookmarks", {
                 return bookmarks.get(args.join(" "), args["-tags"], null, { keyword: context.filter, title: args["-title"] });
             },
             type: CommandOption.STRING,
-            validator: function (arg) /^\S+$/.test(arg)
+            validator: bind("test", /^\S+$/)
         };
 
         commands.add(["bma[rk]"],
             "Add a bookmark",
             function (args) {
+                dactyl.assert(!args.bang || args["-id"] == null,
+                              _("bookmark.bangOrID"));
+
                 let opts = {
                     force: args.bang,
                     unfiled: false,
+                    id: args["-id"],
                     keyword: args["-keyword"] || null,
                     charset: args["-charset"],
                     post: args["-post"],
@@ -449,13 +469,13 @@ var Bookmarks = Module("bookmarks", {
                     url: args.length === 0 ? buffer.uri.spec : args[0]
                 };
 
-                if (bookmarks.add(opts)) {
-                    let extra = (opts.title == opts.url) ? "" : " (" + opts.title + ")";
-                    dactyl.echomsg({ domains: [util.getHost(opts.url)], message: _("bookmark.added", opts.url + extra) },
-                                   1, commandline.FORCE_SINGLELINE);
-                }
-                else
-                    dactyl.echoerr(_("bookmark.cantAdd", opts.title.quote()));
+                let updated = bookmarks.add(opts);
+                let action  = updated ? "updated" : "added";
+
+                let extra   = (opts.title == opts.url) ? "" : " (" + opts.title + ")";
+
+                dactyl.echomsg({ domains: [util.getHost(opts.url)], message: _("bookmark." + action, opts.url + extra) },
+                               1, commandline.FORCE_SINGLELINE);
             }, {
                 argCount: "?",
                 bang: true,
@@ -477,6 +497,11 @@ var Bookmarks = Module("bookmarks", {
                         type: CommandOption.STRING,
                         completer: function (context) completion.charset(context),
                         validator: Option.validateCompleter
+                    },
+                    {
+                        names: ["-id"],
+                        description: "The ID of the bookmark to update",
+                        type: CommandOption.INT
                     }
                 ]
             });
@@ -553,6 +578,7 @@ var Bookmarks = Module("bookmarks", {
                 if (bmarks.length == 1) {
                     let bmark = bmarks[0];
 
+                    options["-id"] = bmark.id;
                     options["-title"] = bmark.title;
                     if (bmark.charset)
                         options["-charset"] = bmark.charset;
@@ -627,6 +653,7 @@ var Bookmarks = Module("bookmarks", {
                 context.fork("keyword/" + keyword, keyword.length + space.length, null, function (context) {
                     context.format = history.format;
                     context.title = [/*L*/keyword + " Quick Search"];
+                    context.keys = { text: "url", description: "title", icon: "icon" };
                     // context.background = true;
                     context.compare = CompletionContext.Sort.unsorted;
                     context.generate = function () {
@@ -663,15 +690,19 @@ var Bookmarks = Module("bookmarks", {
             let engineList = (engineAliases || options["suggestengines"].join(",") || "google").split(",");
 
             engineList.forEach(function (name) {
+                var desc = name;
                 let engine = bookmarks.searchEngines[name];
-                if (!engine)
+                if (engine)
+                    var desc = engine.description;
+                else if (!Set.has(bookmarks.suggestionProviders, name))
                     return;
+
                 let [, word] = /^\s*(\S+)/.exec(context.filter) || [];
                 if (!kludge && word == name) // FIXME: Check for matching keywords
                     return;
                 let ctxt = context.fork(name, 0);
 
-                ctxt.title = [/*L*/engine.description + " Suggestions"];
+                ctxt.title = [/*L*/desc + " Suggestions"];
                 ctxt.keys = { text: util.identity, description: function () "" };
                 ctxt.compare = CompletionContext.Sort.unsorted;
                 ctxt.filterFunc = null;
@@ -689,9 +720,9 @@ var Bookmarks = Module("bookmarks", {
             });
         };
 
-        completion.addUrlCompleter("S", "Suggest engines", completion.searchEngineSuggest);
-        completion.addUrlCompleter("b", "Bookmarks", completion.bookmark);
-        completion.addUrlCompleter("s", "Search engines and keyword URLs", completion.search);
+        completion.addUrlCompleter("suggestion", "Search engine suggestions", completion.searchEngineSuggest);
+        completion.addUrlCompleter("bookmark", "Bookmarks", completion.bookmark);
+        completion.addUrlCompleter("search", "Search engines and keyword URLs", completion.search);
     }
 });