1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-21 09:48:00 +01:00

Add ;S ‘add search keyword’ hint mode.

This commit is contained in:
Kris Maglione
2010-10-09 16:45:22 -04:00
parent 8fb31f7696
commit fdddfb31ef
11 changed files with 178 additions and 76 deletions

View File

@@ -32,6 +32,10 @@ const Bookmarks = Module("bookmarks", {
// if starOnly = true it is saved in the unfiledBookmarksFolder, otherwise in the bookmarksMenuFolder // if starOnly = true it is saved in the unfiledBookmarksFolder, otherwise in the bookmarksMenuFolder
add: function add(starOnly, title, url, keyword, tags, force) { add: function add(starOnly, title, url, keyword, tags, force) {
// FIXME
if (isObject(starOnly))
var { starOnly, title, url, keyword, tags, post, force } = starOnly;
try { try {
let uri = util.createURI(url); let uri = util.createURI(url);
if (!force && bookmarks.isBookmarked(uri.spec)) if (!force && bookmarks.isBookmarked(uri.spec))
@@ -54,6 +58,7 @@ const Bookmarks = Module("bookmarks", {
if (!id) if (!id)
return false; return false;
PlacesUtils.setPostDataForBookmark(id, post);
if (keyword) if (keyword)
services.get("bookmarks").setKeywordForBookmark(id, keyword); services.get("bookmarks").setKeywordForBookmark(id, keyword);
} }
@@ -65,6 +70,17 @@ const Bookmarks = Module("bookmarks", {
return true; return true;
}, },
addSearchKeyword: function (elem) {
let [url, post] = util.parseForm(elem);
let options = { "-title": "Search " + elem.ownerDocument.title };
if (post != null)
options["-post"] = post;
commandline.open(":",
commands.commandToString({ command: "bmark", options: options, arguments: [url] }) + " -keyword ",
modes.EX);
},
toggle: function toggle(url) { toggle: function toggle(url) {
if (!url) if (!url)
return; return;
@@ -104,11 +120,16 @@ const Bookmarks = Module("bookmarks", {
.getBookmarkIdsForURI(uri, {}) .getBookmarkIdsForURI(uri, {})
.filter(bookmarkcache.closure.isRegularBookmark); .filter(bookmarkcache.closure.isRegularBookmark);
} }
bmarks.forEach(services.get("bookmarks").removeItem); bmarks.forEach(function (id) {
let bmark = bookmarkcache.bookmarks[id];
if (bmark)
PlacesUtils.tagging.untagURI(util.newURI(bmark.url), null);
services.get("bookmarks").removeItem(id);
});
return bmarks.length; return bmarks.length;
} }
catch (e) { catch (e) {
dactyl.reportError(e); dactyl.reportError(e, true);
return 0; return 0;
} }
}, },
@@ -132,7 +153,7 @@ const Bookmarks = Module("bookmarks", {
if (engine.alias != alias) if (engine.alias != alias)
engine.alias = alias; engine.alias = alias;
searchEngines.push([engine.alias, engine.description, engine.iconURI && engine.iconURI.spec]); searchEngines.push({ keyword: engine.alias, title: engine.description, icon: engine.iconURI && engine.iconURI.spec });
} }
return searchEngines; return searchEngines;
@@ -286,10 +307,9 @@ const Bookmarks = Module("bookmarks", {
args.completeFilter = have.pop(); args.completeFilter = have.pop();
let prefix = filter.substr(0, filter.length - args.completeFilter.length); let prefix = filter.substr(0, filter.length - args.completeFilter.length);
let tags = array.uniq(array.flatten([b.tags for ([k, b] in Iterator(bookmarkcache.bookmarks)) if (b.tags)])); context.generate = function () array(b.tags for (b in bookmarkcache) if (b.tags)).flatten().uniq().array;
context.keys = { text: function (tag) prefix + tag, description: util.identity };
context.keys = { text: 0, description: 1 }; context.filters.push(function (tag) have.indexOf(tag) < 0);
return [[prefix + tag, tag] for ([i, tag] in Iterator(tags)) if (have.indexOf(tag) < 0)];
}, },
type: CommandOption.LIST type: CommandOption.LIST
}; };
@@ -310,6 +330,17 @@ const Bookmarks = Module("bookmarks", {
type: CommandOption.STRING type: CommandOption.STRING
}; };
const post = {
names: ["-post", "-p"],
description: "Bookmark POST data",
completer: function post(context, args) {
context.keys.text = "post";
context.keys.description = "url";
return bookmarks.get(args.join(" "), args["-tags"], null, { keyword: args["-keyword"], post: context.filter });
},
type: CommandOption.STRING
};
const keyword = { const keyword = {
names: ["-keyword", "-k"], names: ["-keyword", "-k"],
description: "Keyword by which this bookmark may be opened (:open {keyword})", description: "Keyword by which this bookmark may be opened (:open {keyword})",
@@ -324,18 +355,23 @@ const Bookmarks = Module("bookmarks", {
commands.add(["bma[rk]"], commands.add(["bma[rk]"],
"Add a bookmark", "Add a bookmark",
function (args) { function (args) {
let url = args.length == 0 ? buffer.URL : args[0]; let opts = {
let title = args["-title"] || (args.length == 0 ? buffer.title : null); force: args.bang,
let keyword = args["-keyword"] || null; starOnly: false,
let tags = args["-tags"] || []; keyword: args["-keyword"] || null,
post: args["-post"] || null,
tags: args["-tags"] || [],
title: args["-title"] || (args.length === 0 ? buffer.title : null),
url: args.length === 0 ? buffer.URL : args[0]
};
if (bookmarks.add(false, title, url, keyword, tags, args.bang)) { if (bookmarks.add(opts)) {
let extra = (title == url) ? "" : " (" + title + ")"; let extra = (opts.title == opts.url) ? "" : " (" + opts.title + ")";
dactyl.echomsg({ domains: [util.getHost(url)], message: "Added bookmark: " + url + extra }, dactyl.echomsg({ domains: [util.getHost(opts.url)], message: "Added bookmark: " + opts.url + extra },
1, commandline.FORCE_SINGLELINE); 1, commandline.FORCE_SINGLELINE);
} }
else else
dactyl.echoerr("Exxx: Could not add bookmark " + title.quote(), commandline.FORCE_SINGLELINE); dactyl.echoerr("Exxx: Could not add bookmark " + opts.title.quote(), commandline.FORCE_SINGLELINE);
}, { }, {
argCount: "?", argCount: "?",
bang: true, bang: true,
@@ -350,7 +386,7 @@ const Bookmarks = Module("bookmarks", {
} }
completion.bookmark(context, args["-tags"], { keyword: args["-keyword"], title: args["-title"] }); completion.bookmark(context, args["-tags"], { keyword: args["-keyword"], title: args["-title"] });
}, },
options: [title, tags, keyword] options: [keyword, title, tags, post]
}); });
commands.add(["bmarks"], commands.add(["bmarks"],
@@ -383,7 +419,7 @@ const Bookmarks = Module("bookmarks", {
commandline.input("This will delete all bookmarks. Would you like to continue? (yes/[no]) ", commandline.input("This will delete all bookmarks. Would you like to continue? (yes/[no]) ",
function (resp) { function (resp) {
if (resp && resp.match(/^y(es)?$/i)) { if (resp && resp.match(/^y(es)?$/i)) {
bookmarkcache.bookmarks.forEach(function (bmark) { services.get("bookmarks").removeItem(bmark.id); }); Object.keys(bookmarkcache.bookmarks).forEach(function (id) { services.get("bookmarks").removeItem(id); });
dactyl.echomsg("All bookmarks deleted", 1, commandline.FORCE_SINGLELINE); dactyl.echomsg("All bookmarks deleted", 1, commandline.FORCE_SINGLELINE);
} }
}); });
@@ -477,7 +513,7 @@ const Bookmarks = Module("bookmarks", {
if (v != null) if (v != null)
context.filters.push(function (item) item.item[k] != null && this.matchString(v, item.item[k])); context.filters.push(function (item) item.item[k] != null && this.matchString(v, item.item[k]));
}); });
context.completions = bookmarkcache.bookmarks; context.generate = function () values(bookmarkcache.bookmarks);
completion.urls(context, tags); completion.urls(context, tags);
}; };
@@ -487,8 +523,8 @@ const Bookmarks = Module("bookmarks", {
let engines = bookmarks.getSearchEngines(); let engines = bookmarks.getSearchEngines();
context.title = ["Search Keywords"]; context.title = ["Search Keywords"];
context.completions = keywords.concat(engines); context.completions = array(values(keywords)).concat(engines).array;
context.keys = { text: 0, description: 1, icon: 2 }; context.keys = { text: "keyword", description: "title", icon: "icon" };
if (!space || noSuggest) if (!space || noSuggest)
return; return;
@@ -496,7 +532,7 @@ const Bookmarks = Module("bookmarks", {
context.fork("suggest", keyword.length + space.length, this, "searchEngineSuggest", context.fork("suggest", keyword.length + space.length, this, "searchEngineSuggest",
keyword, true); keyword, true);
let item = keywords.filter(function (k) k.keyword == keyword)[0]; let item = keywords[keyword];
if (item && item.url.indexOf("%s") > -1) if (item && item.url.indexOf("%s") > -1)
context.fork("keyword/" + keyword, keyword.length + space.length, null, function (context) { context.fork("keyword/" + keyword, keyword.length + space.length, null, function (context) {
context.format = history.format; context.format = history.format;

View File

@@ -1651,7 +1651,7 @@ const Buffer = Module("buffer", {
let elements = frames.map(function (win) [m for (m in util.evaluateXPath(xpath, win.document))]) let elements = frames.map(function (win) [m for (m in util.evaluateXPath(xpath, win.document))])
.flatten().filter(function (elem) { .flatten().filter(function (elem) {
if (elem.readOnly || elem instanceof HTMLInputElement && !set.has(Events.editableInputs, elem.type)) if (elem.readOnly || elem instanceof HTMLInputElement && !set.has(util.editableInputs, elem.type))
return false; return false;
let computedStyle = util.computedStyle(elem); let computedStyle = util.computedStyle(elem);

View File

@@ -294,7 +294,8 @@ const Dactyl = Module("dactyl", {
if (!context) if (!context)
context = userContext; context = userContext;
return Cu.evalInSandbox("with (window) {" + str + "}", context, "1.8", fileName, lineNumber); context[EVAL_STRING] = str;
return Cu.evalInSandbox("with (window) { eval(" + EVAL_STRING + ") }", context, "1.8", fileName, lineNumber);
}, },
/** /**

View File

@@ -670,7 +670,7 @@ const Events = Module("events", {
// displayed too. --djk // displayed too. --djk
function isInputField() { function isInputField() {
let elem = dactyl.focus; let elem = dactyl.focus;
return elem instanceof HTMLInputElement && set.has(Events.editableInputs, elem.type) return elem instanceof HTMLInputElement && set.has(util.editableInputs, elem.type)
|| elem instanceof HTMLIsIndexElement; || elem instanceof HTMLIsIndexElement;
} }
@@ -738,7 +738,7 @@ const Events = Module("events", {
if (elem && elem.readOnly) if (elem && elem.readOnly)
return; return;
if (elem instanceof HTMLInputElement && set.has(Events.editableInputs, elem.type) || if (elem instanceof HTMLInputElement && set.has(util.editableInputs, elem.type) ||
elem instanceof HTMLSelectElement) { elem instanceof HTMLSelectElement) {
dactyl.mode = modes.INSERT; dactyl.mode = modes.INSERT;
if (hasHTMLDocument(win)) if (hasHTMLDocument(win))
@@ -1075,9 +1075,6 @@ const Events = Module("events", {
// } // }
} }
}, { }, {
editableInputs: set(["date", "datetime", "datetime-local", "email", "file",
"month", "number", "password", "range", "search",
"tel", "text", "time", "url", "week"]),
isContentNode: function (node) { isContentNode: function (node) {
let win = (node.ownerDocument || node).defaultView; let win = (node.ownerDocument || node).defaultView;
for (; win; win = win.parent != win && win.parent) for (; win; win = win.parent != win && win.parent)
@@ -1087,7 +1084,7 @@ const Events = Module("events", {
}, },
isInputElemFocused: function () { isInputElemFocused: function () {
let elem = dactyl.focus; let elem = dactyl.focus;
return elem instanceof HTMLInputElement && set.has(Events.editableInputs, elem.type) || return elem instanceof HTMLInputElement && set.has(util.editableInputs, elem.type) ||
isinstance(elem, [HTMLIsIndexElement, HTMLEmbedElement, isinstance(elem, [HTMLIsIndexElement, HTMLEmbedElement,
HTMLObjectElement, HTMLTextAreaElement]); HTMLObjectElement, HTMLTextAreaElement]);
} }

View File

@@ -54,9 +54,10 @@ const Hints = Module("hints", {
this.addMode("t", "Follow hint in a new tab", function (elem) buffer.followLink(elem, dactyl.NEW_TAB)); this.addMode("t", "Follow hint in a new tab", function (elem) buffer.followLink(elem, dactyl.NEW_TAB));
this.addMode("b", "Follow hint in a background tab", function (elem) buffer.followLink(elem, dactyl.NEW_BACKGROUND_TAB)); this.addMode("b", "Follow hint in a background tab", function (elem) buffer.followLink(elem, dactyl.NEW_BACKGROUND_TAB));
this.addMode("w", "Follow hint in a new window", function (elem) buffer.followLink(elem, dactyl.NEW_WINDOW)); this.addMode("w", "Follow hint in a new window", function (elem) buffer.followLink(elem, dactyl.NEW_WINDOW));
this.addMode("O", "Generate an ':open URL' using hint", function (elem, loc) commandline.open(":", "open " + loc, modes.EX)); this.addMode("O", "Generate an :open URL prompt", function (elem, loc) commandline.open(":", "open " + loc, modes.EX));
this.addMode("T", "Generate a ':tabopen URL' using hint", function (elem, loc) commandline.open(":", "tabopen " + loc, modes.EX)); this.addMode("T", "Generate a :tabopen URL prompt", function (elem, loc) commandline.open(":", "tabopen " + loc, modes.EX));
this.addMode("W", "Generate a ':winopen URL' using hint", function (elem, loc) commandline.open(":", "winopen " + loc, modes.EX)); this.addMode("W", "Generate a :winopen URL prompt", function (elem, loc) commandline.open(":", "winopen " + loc, modes.EX));
this.addMode("S", "Add a search keyword", function (elem) bookmarks.addSearchKeyword(elem));
this.addMode("v", "View hint source", function (elem, loc) buffer.viewSource(loc, false)); this.addMode("v", "View hint source", function (elem, loc) buffer.viewSource(loc, false));
this.addMode("V", "View hint source in external editor", function (elem, loc) buffer.viewSource(loc, true)); this.addMode("V", "View hint source in external editor", function (elem, loc) buffer.viewSource(loc, true));
this.addMode("y", "Yank hint location", function (elem, loc) dactyl.clipboardWrite(loc, true)); this.addMode("y", "Yank hint location", function (elem, loc) dactyl.clipboardWrite(loc, true));
@@ -128,7 +129,7 @@ const Hints = Module("hints", {
let type = elem.type; let type = elem.type;
if (elem instanceof HTMLInputElement && set.has(Events.editableInputs, elem.type)) if (elem instanceof HTMLInputElement && set.has(util.editableInputs, elem.type))
return [elem.value, false]; return [elem.value, false];
else { else {
for (let [, option] in Iterator(options["hintinputs"])) { for (let [, option] in Iterator(options["hintinputs"])) {
@@ -494,7 +495,8 @@ const Hints = Module("hints", {
if ((modes.extended & modes.HINTS) && !this._continue) if ((modes.extended & modes.HINTS) && !this._continue)
modes.pop(); modes.pop();
commandline._lastEcho = null; // Hack. commandline._lastEcho = null; // Hack.
this._hintMode.action(elem, elem.href || elem.src || "", dactyl.trapErrors(this._hintMode.action, this._hintMode,
elem, elem.href || elem.src || "",
this._extendedhintCount, top); this._extendedhintCount, top);
}, timeout); }, timeout);
return true; return true;
@@ -766,7 +768,7 @@ const Hints = Module("hints", {
this._hintMode = this._hintModes[minor]; this._hintMode = this._hintModes[minor];
dactyl.assert(this._hintMode); dactyl.assert(this._hintMode);
commandline.input(this._hintMode.prompt + ": ", null, { commandline.input(UTF8(this._hintMode.prompt) + ": ", null, {
extended: modes.HINTS, extended: modes.HINTS,
leave: function () { hints.hide(); }, leave: function () { hints.hide(); },
onChange: this.closure._onInput onChange: this.closure._onInput
@@ -1072,7 +1074,9 @@ const Hints = Module("hints", {
"XPath string of hintable elements activated by ';'", "XPath string of hintable elements activated by ';'",
"regexmap", "[iI]:" + Option.quote(util.makeXPath(["img"])) + "regexmap", "[iI]:" + Option.quote(util.makeXPath(["img"])) +
",[OTivVWy]:" + Option.quote(util.makeXPath( ",[OTivVWy]:" + Option.quote(util.makeXPath(
["{a,area}[@href]", "{img,iframe}[@src]"])), ["{a,area}[@href]", "{img,iframe}[@src]"])) +
",[S]:" + Option.quote(util.makeXPath(
["input[not(@type='hidden')]", "textarea", "button", "select"])),
{ validator: Option.validateXPath }); { validator: Option.validateXPath });
options.add(["hinttags", "ht"], options.add(["hinttags", "ht"],

View File

@@ -100,9 +100,10 @@
<li tag=";t"><em>t</em> to open its location in a new tab</li> <li tag=";t"><em>t</em> to open its location in a new tab</li>
<li tag=";b"><em>b</em> to open its location in a new background tab</li> <li tag=";b"><em>b</em> to open its location in a new background tab</li>
<li tag=";w"><em>w</em> to open its destination in a new window</li> <li tag=";w"><em>w</em> to open its destination in a new window</li>
<li tag=";O"><em>O</em> to generate an <ex>:open</ex> with hint's URL (like <k>;O</k>)</li> <li tag=";O"><em>O</em> to generate an <ex>:open</ex> prompt with hints URL</li>
<li tag=";T"><em>T</em> to generate a <ex>:tabopen</ex> with hint's URL (like <k>;T</k>)</li> <li tag=";T"><em>T</em> to generate a <ex>:tabopen</ex> prompt with hints URL (like <k>;O</k>)</li>
<li tag=";W"><em>W</em> to generate a <ex>:winopen</ex> with hint's URL</li> <li tag=";W"><em>W</em> to generate a <ex>:winopen</ex> prompt with hints URL (like <k>;T</k>)</li>
<li tag=";S"><em>S</em> to add a search keyword for the hints form</li>
<li tag=";v"><em>v</em> to view its destination source</li> <li tag=";v"><em>v</em> to view its destination source</li>
<li tag=";V"><em>V</em> to view its destination source in the external editor</li> <li tag=";V"><em>V</em> to view its destination source in the external editor</li>
<li tag=";y"><em>y</em> to yank its destination location</li> <li tag=";y"><em>y</em> to yank its destination location</li>

View File

@@ -46,18 +46,6 @@
<p>The following options are available,</p> <p>The following options are available,</p>
<dl> <dl>
<dt>-title</dt>
<dd>
The title of the bookmark.
Defaults to the page title, if available, or
<oa>url</oa> otherwise.
(short name <em>-t</em>)
</dd>
<dt>-tags</dt>
<dd>
Comma-separated list of tags for grouping and later
access (short name <em>-T</em>).
</dd>
<dt>-keyword</dt> <dt>-keyword</dt>
<dd> <dd>
A keyword which may be used to open the bookmark via A keyword which may be used to open the bookmark via
@@ -67,6 +55,23 @@
is opened. is opened.
(short name <em>-k</em>) (short name <em>-k</em>)
</dd> </dd>
<dt>-post</dt>
<dd>
Data to be POSTed to the server when the bookmark is
opened.
</dd>
<dt>-tags</dt>
<dd>
Comma-separated list of tags for grouping and later
access (short name <em>-T</em>).
</dd>
<dt>-title</dt>
<dd>
The title of the bookmark.
Defaults to the page title, if available, or
<oa>url</oa> otherwise.
(short name <em>-t</em>)
</dd>
</dl> </dl>
<p> <p>

View File

@@ -560,7 +560,12 @@
[OTivVWy]:'//a[@href] | //xhtml:a[@href] | [OTivVWy]:'//a[@href] | //xhtml:a[@href] |
//area[@href] | //xhtml:area[@href] | //area[@href] | //xhtml:area[@href] |
//img[@src] | //xhtml:img[@src] | //img[@src] | //xhtml:img[@src] |
//iframe[@src] | //xhtml:iframe[@src]'</default> //iframe[@src] | //xhtml:iframe[@src]',
[S]:'//input[not(@type=''hidden'')] |
//xhtml:input[not(@type=''hidden'')] |
//textarea | //xhtml:textarea |
//button | //xhtml:button |
//select | //xhtml:select' </default>
<description> <description>
<p> <p>
Defines specialized XPath expressions for arbitrary Defines specialized XPath expressions for arbitrary

View File

@@ -10,7 +10,7 @@ defineModule("bookmarkcache", {
require: ["services", "storage", "util"] require: ["services", "storage", "util"]
}); });
const Bookmark = Struct("url", "title", "icon", "keyword", "tags", "id"); const Bookmark = Struct("url", "title", "icon", "post", "keyword", "tags", "id");
const Keyword = Struct("keyword", "title", "icon", "url"); const Keyword = Struct("keyword", "title", "icon", "url");
Bookmark.defaultValue("icon", function () BookmarkCache.getFavicon(this.url)); Bookmark.defaultValue("icon", function () BookmarkCache.getFavicon(this.url));
Bookmark.prototype.__defineGetter__("extra", function () [ Bookmark.prototype.__defineGetter__("extra", function () [
@@ -18,12 +18,15 @@ Bookmark.prototype.__defineGetter__("extra", function () [
["tags", this.tags.join(", "), "Tag"] ["tags", this.tags.join(", "), "Tag"]
].filter(function (item) item[1])); ].filter(function (item) item[1]));
const annotation = services.get("annotation");
const bookmarks = services.get("bookmarks"); const bookmarks = services.get("bookmarks");
const history = services.get("history"); const history = services.get("history");
const tagging = services.get("tagging"); const tagging = services.get("tagging");
const name = "bookmark-cache"; const name = "bookmark-cache";
const BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), { const BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), {
POST: "bookmarkProperties/POSTData",
init: function init() { init: function init() {
bookmarks.addObserver(this, false); bookmarks.addObserver(this, false);
}, },
@@ -32,17 +35,14 @@ const BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver),
get bookmarks() Class.replaceProperty(this, "bookmarks", this.load()), get bookmarks() Class.replaceProperty(this, "bookmarks", this.load()),
get keywords() array.toObject([[b.keyword, b] for (b in this) if (b.keyword)]),
rootFolders: ["toolbarFolder", "bookmarksMenuFolder", "unfiledBookmarksFolder"] rootFolders: ["toolbarFolder", "bookmarksMenuFolder", "unfiledBookmarksFolder"]
.map(function (s) bookmarks[s]), .map(function (s) bookmarks[s]),
_deleteBookmark: function deleteBookmark(id) { _deleteBookmark: function deleteBookmark(id) {
let length = this.bookmarks.length; let result = this.bookmarks[item.id] || null;
let result; delete this.bookmarks[id];
this.bookmarks = this.bookmarks.filter(function (item) {
if (item.id == id)
result = item;
return item.id != id;
});
return result; return result;
}, },
@@ -52,7 +52,8 @@ const BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver),
let uri = util.newURI(node.uri); let uri = util.newURI(node.uri);
let keyword = bookmarks.getKeywordForBookmark(node.itemId); let keyword = bookmarks.getKeywordForBookmark(node.itemId);
let tags = tagging.getTagsForURI(uri, {}) || []; let tags = tagging.getTagsForURI(uri, {}) || [];
return Bookmark(node.uri, node.title, node.icon && node.icon.spec, keyword, tags, node.itemId); let post = BookmarkCache.getAnnotation(node.itemId, this.POST);
return Bookmark(node.uri, node.title, node.icon && node.icon.spec, post, keyword, tags, node.itemId);
}, },
readBookmark: function readBookmark(id) { readBookmark: function readBookmark(id) {
@@ -83,11 +84,9 @@ const BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver),
return this.rootFolders.indexOf(root) >= 0; return this.rootFolders.indexOf(root) >= 0;
}, },
get keywords() [Keyword(k.keyword, k.title, k.icon, k.url) for ([, k] in Iterator(this.bookmarks)) if (k.keyword)],
// Should be made thread safe. // Should be made thread safe.
load: function load() { load: function load() {
let bookmarks = []; let bookmarks = {};
let folders = this.rootFolders.slice(); let folders = this.rootFolders.slice();
let query = history.getNewQuery(); let query = history.getNewQuery();
@@ -105,7 +104,7 @@ const BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver),
if (node.type == node.RESULT_TYPE_FOLDER) // folder if (node.type == node.RESULT_TYPE_FOLDER) // folder
folders.push(node.itemId); folders.push(node.itemId);
else if (node.type == node.RESULT_TYPE_URI) // bookmark else if (node.type == node.RESULT_TYPE_URI) // bookmark
bookmarks.push(this._loadBookmark(node)); bookmarks[node.itemId] = this._loadBookmark(node);
} }
// close a container after using it! // close a container after using it!
@@ -119,7 +118,7 @@ const BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver),
if (bookmarks.getItemType(itemId) == bookmarks.TYPE_BOOKMARK) { if (bookmarks.getItemType(itemId) == bookmarks.TYPE_BOOKMARK) {
if (this.isBookmark(itemId)) { if (this.isBookmark(itemId)) {
let bmark = this._loadBookmark(this.readBookmark(itemId)); let bmark = this._loadBookmark(this.readBookmark(itemId));
this.bookmarks.push(bmark); this.bookmarks[bmark.id] = bmark;
storage.fireEvent(name, "add", bmark); storage.fireEvent(name, "add", bmark);
} }
} }
@@ -131,8 +130,12 @@ const BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver),
}, },
onItemChanged: function onItemChanged(itemId, property, isAnnotation, value) { onItemChanged: function onItemChanged(itemId, property, isAnnotation, value) {
if (isAnnotation) if (isAnnotation)
if (property === this.POST)
[property, value] = ["post", BookmarkCache.getAnnotation(itemId, this.POST)];
else
return; return;
let bookmark = bookmarkcache.bookmarks.filter(function (item) item.id == itemId)[0];
let bookmark = this.bookmarks[itemId];
if (bookmark) { if (bookmark) {
if (property == "tags") if (property == "tags")
value = tagging.getTagsForURI(util.newURI(bookmark.url), {}); value = tagging.getTagsForURI(util.newURI(bookmark.url), {});
@@ -143,6 +146,9 @@ const BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver),
} }
} }
}, { }, {
getAnnotation: function getAnnotation(item, anno)
annotation.itemHasAnnotation(item, anno) ?
annotation.getItemAnnotation(item, anno) : null,
getFavicon: function getFavicon(uri) { getFavicon: function getFavicon(uri) {
try { try {
return service.get("favicon").getFaviconImageForPage(util.newURI(uri)).spec; return service.get("favicon").getFaviconImageForPage(util.newURI(uri)).spec;

View File

@@ -18,6 +18,7 @@ const Services = Module("Services", {
this.classes = {}; this.classes = {};
this.services = {}; this.services = {};
this.add("annotation", "@mozilla.org/browser/annotation-service;1", Ci.nsIAnnotationService);
this.add("appStartup", "@mozilla.org/toolkit/app-startup;1", Ci.nsIAppStartup); this.add("appStartup", "@mozilla.org/toolkit/app-startup;1", Ci.nsIAppStartup);
this.add("autoCompleteSearch", "@mozilla.org/autocomplete/search;1?name=history", Ci.nsIAutoCompleteSearch); this.add("autoCompleteSearch", "@mozilla.org/autocomplete/search;1?name=history", Ci.nsIAutoCompleteSearch);
this.add("bookmarks", "@mozilla.org/browser/nav-bookmarks-service;1", Ci.nsINavBookmarksService); this.add("bookmarks", "@mozilla.org/browser/nav-bookmarks-service;1", Ci.nsINavBookmarksService);

View File

@@ -246,6 +246,10 @@ const Util = Module("Util", {
util.dump((msg || "Stack") + "\n" + stack + "\n"); util.dump((msg || "Stack") + "\n" + stack + "\n");
}, },
editableInputs: set(["date", "datetime", "datetime-local", "email", "file",
"month", "number", "password", "range", "search",
"tel", "text", "time", "url", "week"]),
/** /**
* Converts HTML special characters in <b>str</b> to the equivalent HTML * Converts HTML special characters in <b>str</b> to the equivalent HTML
* entities. * entities.
@@ -521,9 +525,7 @@ const Util = Module("Util", {
* @returns {nsIURI} * @returns {nsIURI}
*/ */
// FIXME: createURI needed too? // FIXME: createURI needed too?
newURI: function (uri) { newURI: function (uri, charset, base) services.get("io").newURI(uri, charset, base),
return services.get("io").newURI(uri, null, null);
},
/** /**
* Pretty print a JavaScript object. Use HTML markup to color certain items * Pretty print a JavaScript object. Use HTML markup to color certain items
@@ -641,6 +643,50 @@ const Util = Module("Util", {
return color ? string : [s for each (s in string)].join(""); return color ? string : [s for each (s in string)].join("");
}, },
/**
* Parses the fields of a form and returns a URL/POST-data pair
* that is the equivalent of submitting the form.
*
* @param {nsINode} field One of the fields of the given form.
*/
// Nuances gleaned from browser.jar/content/browser/browser.js
parseForm: function parseForm(field) {
function encode(name, value, param) {
if (param)
value = "%s";
if (post)
return name + "=" + value;
return encodeURIComponent(name) + "=" + (param ? value : encodeURIComponent(value));
}
let form = field.form;
let doc = form.ownerDocument;
let charset = doc.charset;
let uri = util.newURI(doc.baseURI.replace(/\?.*/, ""), charset);
let url = util.newURI(form.action, charset, uri).spec;
let post = form.method.toUpperCase() == "POST";
let elems = [];
if (field instanceof Ci.nsIDOMHTMLInputElement && field.type == "submit")
elems.push(encode(field.name, field.value));
for (let [,elem] in iter(form.elements)) {
if (set.has(util.editableInputs, elem.type)
|| /^(?:hidden|textarea)$/.test(elem.type)
|| elem.checked && /^(?:checkbox|radio)$/.test(elem.type))
elems.push(encode(elem.name, elem.value, elem === field));
else if (elem instanceof Ci.nsIDOMHTMLSelectElement) {
for (let [,opt] in Iterator(elem.options))
if (opt.selected)
elems.push(encode(elem.name, opt.value));
}
}
if (post)
return [url, elems.map(encodeURIComponent).join('&'), elems];
return [url + "?" + elems.join('&'), null];
},
/** /**
* A generator that returns the values between <b>start</b> and <b>end</b>, * A generator that returns the values between <b>start</b> and <b>end</b>,
* in <b>step</b> increments. * in <b>step</b> increments.