mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-22 11:17:58 +01:00
* Standard module format. All modules are explicitly declared as modules, they're created via a constructor and instantiated automatically. They're dependency aware. They stringify properly. * Classes are declared the same way (rather like Structs already were). They also stringify properly. Plus, each instance has a rather nifty closure member that closes all of its methods around 'this', so you can pass them to map, forEach, setTimeout, etc. Modules are themselves classes, with a special metaclass, as it were. * Doug Crockford is dead, metaphorically speaking. Closure-based classes just don't fit into any of the common JavaScript frameworks, and they're inefficient and confusing. Now, all class and module members are accessed explicitly via 'this', which makes it very clear that they're class members and not (e.g.) local variables, without anything nasty like Hungarian notation. * Strictly one module per file. Classes that belong to a module live in the same file. * For the moment, there are quite a few utility functions sitting in base.c, because my class implementation used them, and I haven't had the time or inclination to sort them out. I plan to reconcile them with the current mess that is the util namespace. * Changed bracing style.
234 lines
8.8 KiB
JavaScript
234 lines
8.8 KiB
JavaScript
// Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
|
//
|
|
// This work is licensed for reuse under an MIT license. Details are
|
|
// given in the LICENSE.txt file included with this file.
|
|
|
|
const History = Module("history", {
|
|
get format() bookmarks.format,
|
|
|
|
get service() services.get("history"),
|
|
|
|
get: function get(filter, maxItems) {
|
|
// no query parameters will get all history
|
|
let query = services.get("history").getNewQuery();
|
|
let options = services.get("history").getNewQueryOptions();
|
|
|
|
if (typeof filter == "string")
|
|
filter = { searchTerms: filter };
|
|
for (let [k, v] in Iterator(filter))
|
|
query[k] = v;
|
|
options.sortingMode = options.SORT_BY_DATE_DESCENDING;
|
|
options.resultType = options.RESULTS_AS_URI;
|
|
if (maxItems > 0)
|
|
options.maxResults = maxItems;
|
|
|
|
// execute the query
|
|
let root = services.get("history").executeQuery(query, options).root;
|
|
root.containerOpen = true;
|
|
let items = util.map(util.range(0, root.childCount), function (i) {
|
|
let node = root.getChild(i);
|
|
return {
|
|
url: node.uri,
|
|
title: node.title,
|
|
icon: node.icon ? node.icon.spec : DEFAULT_FAVICON
|
|
};
|
|
});
|
|
root.containerOpen = false; // close a container after using it!
|
|
|
|
return items;
|
|
},
|
|
|
|
get session() {
|
|
let sh = window.getWebNavigation().sessionHistory;
|
|
let obj = [];
|
|
obj.index = sh.index;
|
|
obj.__iterator__ = function () util.Array.iteritems(this);
|
|
for (let i in util.range(0, sh.count)) {
|
|
obj[i] = { index: i, __proto__: sh.getEntryAtIndex(i, false) };
|
|
util.memoize(obj[i], "icon",
|
|
function (obj) services.get("favicon").getFaviconImageForPage(obj.URI).spec);
|
|
}
|
|
return obj;
|
|
},
|
|
|
|
// TODO: better names
|
|
stepTo: function stepTo(steps) {
|
|
let start = 0;
|
|
let end = window.getWebNavigation().sessionHistory.count - 1;
|
|
let current = window.getWebNavigation().sessionHistory.index;
|
|
|
|
if (current == start && steps < 0 || current == end && steps > 0)
|
|
liberator.beep();
|
|
else {
|
|
let index = util.Math.constrain(current + steps, start, end);
|
|
window.getWebNavigation().gotoIndex(index);
|
|
}
|
|
},
|
|
|
|
goToStart: function goToStart() {
|
|
let index = window.getWebNavigation().sessionHistory.index;
|
|
|
|
if (index > 0)
|
|
window.getWebNavigation().gotoIndex(0);
|
|
else
|
|
liberator.beep();
|
|
|
|
},
|
|
|
|
goToEnd: function goToEnd() {
|
|
let sh = window.getWebNavigation().sessionHistory;
|
|
let max = sh.count - 1;
|
|
|
|
if (sh.index < max)
|
|
window.getWebNavigation().gotoIndex(max);
|
|
else
|
|
liberator.beep();
|
|
|
|
},
|
|
|
|
// if openItems is true, open the matching history items in tabs rather than display
|
|
list: function list(filter, openItems, maxItems) {
|
|
// FIXME: returning here doesn't make sense
|
|
// Why the hell doesn't it make sense? --Kris
|
|
// See comment at bookmarks.list --djk
|
|
if (!openItems)
|
|
return completion.listCompleter("history", filter, maxItems);
|
|
let items = completion.runCompleter("history", filter, maxItems);
|
|
|
|
if (items.length)
|
|
return liberator.open(items.map(function (i) i.url), liberator.NEW_TAB);
|
|
|
|
if (filter.length > 0)
|
|
liberator.echoerr("E283: No history matching \"" + filter + "\"");
|
|
else
|
|
liberator.echoerr("No history set");
|
|
}
|
|
}, {
|
|
}, {
|
|
commands: function () {
|
|
commands.add(["ba[ck]"],
|
|
"Go back in the browser history",
|
|
function (args) {
|
|
let url = args.literalArg;
|
|
|
|
if (args.bang)
|
|
history.goToStart();
|
|
else {
|
|
if (url) {
|
|
let sh = history.session;
|
|
if (/^\d+(:|$)/.test(url) && sh.index - parseInt(url) in sh)
|
|
return void window.getWebNavigation().gotoIndex(sh.index - parseInt(url));
|
|
|
|
for (let [i, ent] in Iterator(sh.slice(0, sh.index).reverse()))
|
|
if (ent.URI.spec == url)
|
|
return void window.getWebNavigation().gotoIndex(i);
|
|
liberator.echoerr("Exxx: URL not found in history");
|
|
}
|
|
else
|
|
history.stepTo(-Math.max(args.count, 1));
|
|
}
|
|
},
|
|
{
|
|
argCount: "?",
|
|
bang: true,
|
|
completer: function completer(context) {
|
|
let sh = history.session;
|
|
|
|
context.anchored = false;
|
|
context.compare = CompletionContext.Sort.unsorted;
|
|
context.filters = [CompletionContext.Filter.textDescription];
|
|
context.completions = sh.slice(0, sh.index).reverse();
|
|
context.keys = { text: function (item) (sh.index - item.index) + ": " + item.URI.spec, description: "title", icon: "icon" };
|
|
},
|
|
count: true,
|
|
literal: 0
|
|
});
|
|
|
|
commands.add(["fo[rward]", "fw"],
|
|
"Go forward in the browser history",
|
|
function (args) {
|
|
let url = args.literalArg;
|
|
|
|
if (args.bang)
|
|
history.goToEnd();
|
|
else {
|
|
if (url) {
|
|
let sh = history.session;
|
|
if (/^\d+(:|$)/.test(url) && sh.index + parseInt(url) in sh)
|
|
return void window.getWebNavigation().gotoIndex(sh.index + parseInt(url));
|
|
|
|
for (let [i, ent] in Iterator(sh.slice(sh.index + 1)))
|
|
if (ent.URI.spec == url)
|
|
return void window.getWebNavigation().gotoIndex(i);
|
|
liberator.echoerr("Exxx: URL not found in history");
|
|
}
|
|
else
|
|
history.stepTo(Math.max(args.count, 1));
|
|
}
|
|
},
|
|
{
|
|
argCount: "?",
|
|
bang: true,
|
|
completer: function completer(context) {
|
|
let sh = history.session;
|
|
|
|
context.anchored = false;
|
|
context.compare = CompletionContext.Sort.unsorted;
|
|
context.filters = [CompletionContext.Filter.textDescription];
|
|
context.completions = sh.slice(sh.index + 1);
|
|
context.keys = { text: function (item) (item.index - sh.index) + ": " + item.URI.spec, description: "title", icon: "icon" };
|
|
},
|
|
count: true,
|
|
literal: 0
|
|
});
|
|
|
|
commands.add(["hist[ory]", "hs"],
|
|
"Show recently visited URLs",
|
|
function (args) { history.list(args.join(" "), args.bang, args["-max"] || 1000); }, {
|
|
bang: true,
|
|
completer: function (context) { context.quote = null; completion.history(context); },
|
|
// completer: function (filter) completion.history(filter)
|
|
options: [[["-max", "-m"], commands.OPTION_INT]]
|
|
});
|
|
},
|
|
completion: function () {
|
|
completion.history = function _history(context, maxItems) {
|
|
context.format = history.format;
|
|
context.title = ["History"];
|
|
context.compare = CompletionContext.Sort.unsorted;
|
|
//context.background = true;
|
|
if (context.maxItems == null)
|
|
context.maxItems = 100;
|
|
context.regenerate = true;
|
|
context.generate = function () history.get(context.filter, this.maxItems);
|
|
};
|
|
|
|
completion.addUrlCompleter("h", "History", completion.history);
|
|
},
|
|
mappings: function () {
|
|
var myModes = config.browserModes;
|
|
|
|
mappings.add(myModes,
|
|
["<C-o>"], "Go to an older position in the jump list",
|
|
function (count) { history.stepTo(-Math.max(count, 1)); },
|
|
{ count: true });
|
|
|
|
mappings.add(myModes,
|
|
["<C-i>"], "Go to a newer position in the jump list",
|
|
function (count) { history.stepTo(Math.max(count, 1)); },
|
|
{ count: true });
|
|
|
|
mappings.add(myModes,
|
|
["H", "<A-Left>", "<M-Left>"], "Go back in the browser history",
|
|
function (count) { history.stepTo(-Math.max(count, 1)); },
|
|
{ count: true });
|
|
|
|
mappings.add(myModes,
|
|
["L", "<A-Right>", "<M-Right>"], "Go forward in the browser history",
|
|
function (count) { history.stepTo(Math.max(count, 1)); },
|
|
{ count: true });
|
|
},
|
|
});
|
|
|
|
// vim: set fdm=marker sw=4 ts=4 et:
|