1 // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
2 // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
3 // Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
5 // This work is licensed for reuse under an MIT license. Details are
6 // given in the LICENSE.txt file included with this file.
9 var History = Module("history", {
10 get format() bookmarks.format,
12 get service() services.history,
14 get: function get(filter, maxItems, order) {
15 // no query parameters will get all history
16 let query = services.history.getNewQuery();
17 let options = services.history.getNewQueryOptions();
19 if (typeof filter == "string")
20 filter = { searchTerms: filter };
21 for (let [k, v] in Iterator(filter))
24 order = order || "+date";
25 dactyl.assert((order = /^([+-])(.+)/.exec(order)) &&
26 (order = "SORT_BY_" + order[2].toUpperCase() + "_" +
27 (order[1] == "+" ? "ASCENDING" : "DESCENDING")) &&
29 _("error.invalidSort", order));
31 options.sortingMode = options[order];
32 options.resultType = options.RESULTS_AS_URI;
34 options.maxResults = maxItems;
37 let root = services.history.executeQuery(query, options).root;
38 root.containerOpen = true;
39 let items = iter(util.range(0, root.childCount)).map(function (i) {
40 let node = root.getChild(i);
44 icon: node.icon ? node.icon.spec : DEFAULT_FAVICON
47 root.containerOpen = false; // close a container after using it!
53 let sh = window.getWebNavigation().sessionHistory;
56 obj.__iterator__ = function () array.iterItems(this);
57 for (let i in util.range(0, sh.count)) {
58 obj[i] = update(Object.create(sh.getEntryAtIndex(i, false)),
60 memoize(obj[i], "icon",
61 function () services.favicon.getFaviconImageForPage(this.URI).spec);
66 stepTo: function stepTo(steps) {
68 let end = window.getWebNavigation().sessionHistory.count - 1;
69 let current = window.getWebNavigation().sessionHistory.index;
71 if (current == start && steps < 0 || current == end && steps > 0)
74 let index = Math.constrain(current + steps, start, end);
76 window.getWebNavigation().gotoIndex(index);
78 catch (e) {} // We get NS_ERROR_FILE_NOT_FOUND if files in history don't exist
82 goToStart: function goToStart() {
83 let index = window.getWebNavigation().sessionHistory.index;
86 window.getWebNavigation().gotoIndex(0);
92 goToEnd: function goToEnd() {
93 let sh = window.getWebNavigation().sessionHistory;
94 let max = sh.count - 1;
97 window.getWebNavigation().gotoIndex(max);
103 // if openItems is true, open the matching history items in tabs rather than display
104 list: function list(filter, openItems, maxItems, sort) {
105 // FIXME: returning here doesn't make sense
106 // Why the hell doesn't it make sense? --Kris
107 // See comment at bookmarks.list --djk
109 return completion.listCompleter("history", filter, maxItems, maxItems, sort);
110 let items = completion.runCompleter("history", filter, maxItems, maxItems, sort);
113 return dactyl.open(items.map(function (i) i.url), dactyl.NEW_TAB);
115 if (filter.length > 0)
116 dactyl.echoerr(_("history.noMatching", filter.quote()));
118 dactyl.echoerr(_("history.none"));
123 commands: function () {
124 commands.add(["ba[ck]"],
125 "Go back in the browser history",
133 let sh = history.session;
134 if (/^\d+(:|$)/.test(url) && sh.index - parseInt(url) in sh)
135 return void window.getWebNavigation().gotoIndex(sh.index - parseInt(url));
137 for (let [i, ent] in Iterator(sh.slice(0, sh.index).reverse()))
138 if (ent.URI.spec == url)
139 return void window.getWebNavigation().gotoIndex(i);
140 dactyl.echoerr(_("history.noURL"));
143 history.stepTo(-Math.max(args.count, 1));
150 completer: function completer(context) {
151 let sh = history.session;
153 context.anchored = false;
154 context.compare = CompletionContext.Sort.unsorted;
155 context.filters = [CompletionContext.Filter.textDescription];
156 context.completions = sh.slice(0, sh.index).reverse();
157 context.keys = { text: function (item) (sh.index - item.index) + ": " + item.URI.spec, description: "title", icon: "icon" };
164 commands.add(["fo[rward]", "fw"],
165 "Go forward in the browser history",
167 let url = args.literalArg;
173 let sh = history.session;
174 if (/^\d+(:|$)/.test(url) && sh.index + parseInt(url) in sh)
175 return void window.getWebNavigation().gotoIndex(sh.index + parseInt(url));
177 for (let [i, ent] in Iterator(sh.slice(sh.index + 1)))
178 if (ent.URI.spec == url)
179 return void window.getWebNavigation().gotoIndex(i);
180 dactyl.echoerr(_("history.noURL"));
183 history.stepTo(Math.max(args.count, 1));
190 completer: function completer(context) {
191 let sh = history.session;
193 context.anchored = false;
194 context.compare = CompletionContext.Sort.unsorted;
195 context.filters = [CompletionContext.Filter.textDescription];
196 context.completions = sh.slice(sh.index + 1);
197 context.keys = { text: function (item) (item.index - sh.index) + ": " + item.URI.spec, description: "title", icon: "icon" };
204 commands.add(["hist[ory]", "hs"],
205 "Show recently visited URLs",
206 function (args) { history.list(args.join(" "), args.bang, args["-max"], args["-sort"]); }, {
208 completer: function (context, args) completion.history(context, args["-max"], args["-sort"]),
211 names: ["-max", "-m"],
212 description: "The maximum number of items to list",
214 type: CommandOption.INT
217 names: ["-sort", "-s"],
218 type: CommandOption.STRING,
219 description: "The sort order of the results",
220 completer: function (context, args) {
221 context.compare = CompletionContext.Sort.unsorted;
222 return array.flatten([
232 ].map(function (order) [
233 ["+" + order.replace(" ", ""), "Sort by " + order + " ascending"],
234 ["-" + order.replace(" ", ""), "Sort by " + order + " descending"]
242 completion: function () {
243 completion.domain = function (context) {
244 context.anchored = false;
245 context.compare = function (a, b) String.localeCompare(a.key, b.key);
246 context.keys = { text: util.identity, description: util.identity,
247 key: function (host) host.split(".").reverse().join(".") };
249 // FIXME: Schema-specific
250 context.generate = function () [
251 Array.slice(row.rev_host).reverse().join("").slice(1)
252 for (row in iter(services.history.DBConnection
253 .createStatement("SELECT DISTINCT rev_host FROM moz_places WHERE rev_host IS NOT NULL;")))
257 completion.history = function _history(context, maxItems, sort) {
258 context.format = history.format;
259 context.title = ["History"];
260 context.compare = CompletionContext.Sort.unsorted;
261 //context.background = true;
262 if (maxItems == null)
263 context.maxItems = maxItems;
264 if (maxItems && context.maxItems == null)
265 context.maxItems = 100;
266 context.regenerate = true;
267 context.generate = function () history.get(context.filter, this.maxItems, sort);
270 completion.addUrlCompleter("h", "History", completion.history);
272 mappings: function () {
273 var myModes = config.browserModes;
275 mappings.add(myModes,
276 ["<C-o>"], "Go to an older position in the jump list",
277 function (args) { history.stepTo(-Math.max(args.count, 1)); },
280 mappings.add(myModes,
281 ["<C-i>"], "Go to a newer position in the jump list",
282 function (args) { history.stepTo(Math.max(args.count, 1)); },
285 mappings.add(myModes,
286 ["H", "<A-Left>", "<M-Left>"], "Go back in the browser history",
287 function (args) { history.stepTo(-Math.max(args.count, 1)); },
290 mappings.add(myModes,
291 ["L", "<A-Right>", "<M-Right>"], "Go forward in the browser history",
292 function (args) { history.stepTo(Math.max(args.count, 1)); },
297 // vim: set fdm=marker sw=4 ts=4 et: