diff --git a/common/content/buffer.js b/common/content/buffer.js index b56c571b..27f2114f 100644 --- a/common/content/buffer.js +++ b/common/content/buffer.js @@ -292,7 +292,7 @@ const Buffer = Module("buffer", { // Workaround for bugs 591425 and 606877, dactyl bug #81 config.browser.mCurrentBrowser.collapsed = - uri.scheme === "dactyl" && webProgress.isLoadingDocument; + uri && uri.scheme === "dactyl" && webProgress.isLoadingDocument; util.timeout(function () { autocommands.trigger("LocationChange", { url: buffer.URL }); @@ -480,8 +480,6 @@ const Buffer = Module("buffer", { * * @returns {string} */ - // FIXME: getSelection() doesn't always preserve line endings, see: - // https://www.mozdev.org/bugs/show_bug.cgi?id=19303 getCurrentWord: function () { let win = buffer.focusedFrame || window.content; let selection = win.getSelection(); @@ -1688,11 +1686,11 @@ const Buffer = Module("buffer", { // reloading mappings.add(myModes, ["r"], "Reload the current web page", - function () { tabs.reload(config.browser.mCurrentTab, false); }); + function () { tabs.reload(tabs.getTab(), false); }); mappings.add(myModes, ["R"], "Reload while skipping the cache", - function () { tabs.reload(config.browser.mCurrentTab, true); }); + function () { tabs.reload(tabs.getTab(), true); }); // yanking mappings.add(myModes, ["Y"], diff --git a/common/content/completion.js b/common/content/completion.js index bd5c536e..d5922404 100644 --- a/common/content/completion.js +++ b/common/content/completion.js @@ -864,6 +864,16 @@ const Completion = Module("completion", { if (complete == null) complete = options["complete"]; + if (/^about:/.test(context.filter)) { + context.fork("about", 6, this, function (context) { + context.generate = function () { + const PREFIX = "@mozilla.org/network/protocol/about;1?what="; + return [[k.substr(PREFIX.length), ""] for (k in Cc) if (k.indexOf(PREFIX) == 0)] + } + }); + } + + // Will, and should, throw an error if !(c in opts) Array.forEach(complete, function (c) { let completer = completion.urlCompleters[c]; diff --git a/common/content/io.js b/common/content/io.js index 844b3c2c..3148c30d 100644 --- a/common/content/io.js +++ b/common/content/io.js @@ -209,6 +209,18 @@ const IO = Module("io", { return io.File(file); }, + isJarURL: function (url) { + try { + let uri = util.newURI(url); + let channel = services.io.newChannelFromURI(uri); + channel.cancel(Cr.NS_BINDING_ABORTED); + if (channel instanceof Ci.nsIJARChannel) + return channel.QueryInterface(Ci.nsIJARChannel); + } + catch (e) {} + return false; + }, + readHeredoc: function (end) { return ""; }, @@ -654,7 +666,12 @@ lookup: completion.file = function file(context, full, dir) { // dir == "" is expanded inside readDirectory to the current dir - [dir] = (dir || context.filter).match(/^(?:.*[\/\\])?/); + function getDir(str) str.match(/^(?:.*[\/\\])?/)[0]; + dir = getDir(dir || context.filter); + + let file = util.getFile(dir); + if (file && file.exists() && !file.isDirectory()) + file = file.parent; if (!full) context.advance(dir.length); @@ -677,13 +694,40 @@ lookup: // context.background = true; context.key = dir; - context.generate = function generate_file() { - try { - return io.File(dir).readDirectory(); - } - catch (e) {} - return []; - }; + let channel = io.isJarURL(dir); + if (channel) + context.generate = function generate_jar() { + let uri = channel.URI.QueryInterface(Ci.nsIJARURI); + let file = util.getFile(uri.JARFile); + if (file) { + // let jar = services.zipReader.getZip(file); Crashes. + let jar = services.ZipReader(file); + try { + let path = decodeURI(getDir(uri.JAREntry)); + return [ + { + isDirectory: function () s.substr(-1) == "/", + leafName: /([^\/]*)\/?$/.exec(s)[1] + } + for (s in iter(jar.findEntries("*"))) if (s.indexOf(path) == 0) + ] + } + finally { + jar.close(); + } + } + }; + else + context.generate = function generate_file() { + try { + util.dump(String(file), file && file.path); + return io.File(file || dir).readDirectory(); + } + catch (e) { + util.reportError(e); + } + return []; + }; }; completion.runtime = function (context) { @@ -715,7 +759,17 @@ lookup: }; completion.addUrlCompleter("f", "Local files", function (context, full) { - if (/^(\.{0,2}|~)\/|^file:/.test(context.filter)) + let match = /^(chrome:\/\/[^\/]+\/)([^/]*)$/.exec(context.filter); + if (match) { + context.key = match[1]; + context.advance(match[1].length); + context.generate = function () iter({ + content: "Chrome content", + locale: "Locale-specific content", + skin: "Theme-specific content" + }); + } + else if (/^(\.{0,2}|~)\/|^file:/.test(context.filter) || util.getFile(context.filter) || io.isJarURL(context.filter)) completion.file(context, full); }); }, diff --git a/common/content/modes.js b/common/content/modes.js index 1e66cb1f..4f352bb7 100644 --- a/common/content/modes.js +++ b/common/content/modes.js @@ -23,10 +23,8 @@ const Modes = Module("modes", { this._modeStack = update([], { pop: function pop() { - if (this.length <= 1) { - util.dumpStack("Trying to pop last element in mode stack"); + if (this.length <= 1) throw Error("Trying to pop last element in mode stack"); - } return pop.superapply(this, arguments); } }); @@ -47,7 +45,7 @@ const Modes = Module("modes", { if (selection && !selection.isCollapsed) selection.collapseToStart(); } - else + else if (stack.pop) editor.unselectText(); } }); @@ -96,10 +94,12 @@ const Modes = Module("modes", { dactyl.focusContent(true); if (prev.main == modes.NORMAL) { dactyl.focusContent(true); - // clear any selection made - let selection = window.content.getSelection(); - if (selection && !selection.isCollapsed) - selection.collapseToStart(); + for (let frame in values(buffer.allFrames())) { + // clear any selection made + let selection = frame.getSelection(); + if (selection && !selection.isCollapsed) + selection.collapseToStart(); + } } } diff --git a/common/content/tabs.js b/common/content/tabs.js index 938b1e65..f2be4187 100644 --- a/common/content/tabs.js +++ b/common/content/tabs.js @@ -445,7 +445,7 @@ const Tabs = Module("tabs", { else { let index = (count - 1) % matches.length; if (reverse) - index = matches.length - count; + index = matches.length - index - 1; tabs.select(matches[index].id, false); } }, diff --git a/common/locale/en-US/various.xml b/common/locale/en-US/various.xml index a491b58c..db65a99e 100644 --- a/common/locale/en-US/various.xml +++ b/common/locale/en-US/various.xml @@ -195,10 +195,11 @@

- The following items are cleared regardless of timeframe: - cache, offlineapps, passwords, - sessions, sitesettings. Additionally, - options are never cleared. + The following items are always cleared entirely, regardless of + timeframe: cache, offlineapps, + passwords, sessions, sitesettings. + Conversely, options are never cleared unless a host is + specified.

@@ -235,7 +236,7 @@

Available actions:

-
+
unset
Unset special permissions for host
allow
Allow cookies from host
deny
Deny cookies from host
@@ -250,7 +251,7 @@ If no action is given, the value of cookies is used.

- :map -b c :cookies + :map -b c :cookies diff --git a/common/modules/sanitizer.jsm b/common/modules/sanitizer.jsm index cb3226f6..93a8642e 100644 --- a/common/modules/sanitizer.jsm +++ b/common/modules/sanitizer.jsm @@ -27,6 +27,9 @@ Range.prototype.contains = function (date) date == null || (this.min == null || date >= this.min) && (this.max == null || date <= this.max); Range.prototype.__defineGetter__("isEternity", function () this.max == null && this.min == null); Range.prototype.__defineGetter__("isSession", function () this.max == null && this.min == sanitizer.sessionStart); +Range.prototype.__defineGetter__("native", function () + this.isEternity ? null : [range.min || 0, range.max == null ? Number.MAX_VALUE : range.max]); + const Item = Class("Item", { init: function (name) { @@ -266,7 +269,7 @@ const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakR try { let item = this.items[Sanitizer.argToPref(itemName)]; if (item && !this.itemMap[itemName].override) { - item.range = range; + item.range = range.native; if ("clear" in item && item.canClear) item.clear(); } @@ -369,12 +372,16 @@ const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakR let timespan = args["-timespan"] || modules.options["sanitizetimespan"]; - let range = Range(), match = /^(\d+)([mhdw])$/.exec(timespan); + let range = Range(); + let [match, num, unit] = /^(\d+)([mhdw])$/.exec(timespan) || []; range[args["-older"] ? "max" : "min"] = - match ? 1000 * (Date.now() - 1000 * parseInt(match[1], 10) * { m: 60, h: 3600, d: 3600 * 24, w: 3600 * 24 * 7 }[match[2]]) + match ? 1000 * (Date.now() - 1000 * parseInt(num, 10) * { m: 60, h: 3600, d: 3600 * 24, w: 3600 * 24 * 7 }[unit]) : (timespan[0] == "s" ? sanitizer.sessionStart : null); let items = args.slice(); + if (args["-host"] && !args.length) + args[0] = "all"; + if (args.bang) { dactyl.assert(args.length == 0, "E488: Trailing characters"); items = Object.keys(sanitizer.itemMap).filter( @@ -386,7 +393,7 @@ const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakR if (items.indexOf("all") >= 0) items = Object.keys(sanitizer.itemMap).filter(function (k) items.indexOf(k) === -1); - sanitizer.range = range; + sanitizer.range = range.native; sanitizer.ignoreTimespan = range.min == null; sanitizer.sanitizing = true; if (args["-host"]) { @@ -412,11 +419,9 @@ const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakR { names: ["-host", "-h"], description: "Only sanitize items referring to listed host or hosts", - completer: function (context) { - let hosts = context.filter.split(","); - context.advance(context.filter.length - hosts.pop().length); + completer: function (context, args) { context.filters.push(function (item) - !hosts.some(function (host) util.isSubdomain(item.text, host))); + !args["-host"].some(function (host) util.isSubdomain(item.text, host))); modules.completion.domain(context); }, type: modules.CommandOption.LIST, diff --git a/common/modules/services.jsm b/common/modules/services.jsm index 561d30f1..4199f2ca 100644 --- a/common/modules/services.jsm +++ b/common/modules/services.jsm @@ -58,6 +58,7 @@ const Services = Module("Services", { this.add("versionCompare", "@mozilla.org/xpcom/version-comparator;1", Ci.nsIVersionComparator); this.add("windowMediator", "@mozilla.org/appshell/window-mediator;1", Ci.nsIWindowMediator); this.add("windowWatcher", "@mozilla.org/embedcomp/window-watcher;1", Ci.nsIWindowWatcher); + this.add("zipReader", "@mozilla.org/libjar/zip-reader-cache;1", Ci.nsIZipReaderCache); this.addClass("File", "@mozilla.org/file/local;1", Ci.nsILocalFile); this.addClass("file:", "@mozilla.org/network/protocol;1?name=file", Ci.nsIFileProtocolHandler); @@ -68,15 +69,18 @@ const Services = Module("Services", { this.addClass("String", "@mozilla.org/supports-string;1", Ci.nsISupportsString); this.addClass("Timer", "@mozilla.org/timer;1", Ci.nsITimer); this.addClass("Xmlhttp", "@mozilla.org/xmlextras/xmlhttprequest;1", Ci.nsIXMLHttpRequest); + this.addClass("ZipReader", "@mozilla.org/libjar/zip-reader;1", Ci.nsIZipReader, "open"); this.addClass("ZipWriter", "@mozilla.org/zipwriter;1", Ci.nsIZipWriter); }, - _create: function (classes, ifaces, meth) { + _create: function (classes, ifaces, meth, init, args) { try { let res = Cc[classes][meth || "getService"](); if (!ifaces) return res.wrappedJSObject; Array.concat(ifaces).forEach(function (iface) res.QueryInterface(iface)); + if (init) + res[init].apply(res, args); return res; } catch (e) { @@ -113,9 +117,9 @@ const Services = Module("Services", { * @param {nsISupports|nsISupports[]} ifaces The interface or array of * interfaces implemented by this class. */ - addClass: function (name, class_, ifaces) { + addClass: function (name, class_, ifaces, init) { const self = this; - return this[name] = function () self._create(class_, ifaces, "createInstance"); + return this[name] = function () self._create(class_, ifaces, "createInstance", init, arguments); }, /** diff --git a/common/modules/util.jsm b/common/modules/util.jsm index 7261e780..681a97e5 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -471,7 +471,12 @@ const Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]) */ getFile: function getFile(uri) { if (isString(uri)) - uri = util.newURI(uri); + try { + uri = util.newURI(uri); + } + catch (e) { + return null; + } if (uri instanceof Ci.nsIFileURL) return File(uri.QueryInterface(Ci.nsIFileURL).file);