diff --git a/common/content/browser.js b/common/content/browser.js index 292c0c53..09a194c2 100644 --- a/common/content/browser.js +++ b/common/content/browser.js @@ -188,6 +188,7 @@ const Browser = Module("browser", { function () { window.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils).redraw(); + statusline.updateUrl(); commandline.clear(); }, { argCount: "0" }); diff --git a/common/content/buffer.js b/common/content/buffer.js index f8a30123..c90aa6e3 100644 --- a/common/content/buffer.js +++ b/common/content/buffer.js @@ -932,11 +932,12 @@ const Buffer = Module("buffer", { * @param {boolean} useExternalEditor View the source in the external editor. */ viewSource: function (url, useExternalEditor) { - url = url || buffer.URI; + let doc = tabs.localStore.focusedFrame.document; if (useExternalEditor) - editor.editFileExternally(url); + this.viewSourceExternally(url || doc); else { + url = url || doc.location.href; const PREFIX = "view-source:"; if (url.indexOf(PREFIX) == 0) url = url.substr(PREFIX.length); @@ -951,6 +952,92 @@ const Buffer = Module("buffer", { } }, + /** + * Launches an editor to view the source of the given document. The + * contents of the document are saved to a temporary local file and + * removed when the editor returns. This function returns + * immediately. + * + * @param {Document} doc The document to view. + */ + /* + * Derived from code in Mozilla, ©2005 Jason Barnabe, + * Tri-licensed under MPL 1.1/GPL 2.0/LGPL 2.1 + * Portions copyright Kris Maglione licensable under the + * MIT license. + */ + viewSourceExternally: Class("viewSourceExternally", + XPCOM([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]), { + init: function (doc) { + let url = isString(doc) ? doc : doc.location.href; + let charset = isString(doc) ? null : doc.characterSet; + + let webNav = window.getWebNavigation(); + try { + webNav = doc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(nsIWebNavigation); + } + catch (e) {} + let descriptor = null; + try { + descriptor = webNav.QueryInterface(Ci.nsIWebPageDescriptor).currentDescriptor; + } + catch (e) {} + + let uri = util.newURI(url, charset); + if (uri.scheme == "file") + editor.editFileExternally(uri.QueryInterface(Ci.nsIFileURL).file.path); + else { + if (descriptor) { + // we'll use nsIWebPageDescriptor to get the source because it may + // not have to refetch the file from the server + // XXXbz this is so broken... This code doesn't set up this docshell + // at all correctly; if somehow the view-source stuff managed to + // execute script we'd be in big trouble here, I suspect. + + this.docShell = Cc["@mozilla.org/docshell;1"].createInstance(Ci.nsIBaseWindow) + .QueryInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIWebPageDescriptor) + .QueryInterface(Ci.nsIWebProgress); + this.docShell.create(); + this.docShell.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT); + this.docShell.loadPage(descriptor, Ci.nsIWebPageDescriptor.DISPLAY_AS_SOURCE); + } + else { + this.file = io.createTempFile(); + var webBrowserPersist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"] + .createInstance(Ci.nsIWebBrowserPersist); + webBrowserPersist.persistFlags = Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES; + webBrowserPersist.progressListener = this; + webBrowserPersist.saveURI(uri, null, null, null, null, this.file); + } + } + return null; + }, + + destroy: function() { + if (this.docShell) + this.docShell.destroy(); + }, + + onStateChange: function(progress, request, flag, status) { + // once it's done loading... + if ((flag & Ci.nsIWebProgressListener.STATE_STOP) && status == 0) { + try { + if (this.docShell) { + this.file = io.createTempFile(); + this.file.write(this.docShell.document.body.textContent); + } + editor.editFileExternally(this.file.path); + this.file.remove(false); + } + finally { + this.destroy(); + } + } + return 0; + } + }), + /** * Increases the zoom level of the current buffer. * diff --git a/common/content/io.js b/common/content/io.js index e95c2547..0402c395 100644 --- a/common/content/io.js +++ b/common/content/io.js @@ -11,12 +11,13 @@ plugins.contexts = {}; function Script(file) { - let self = plugins.contexts[file.path]; + let self = plugins[file.path]; if (self) { if (self.onUnload) self.onUnload(); return self; - } + } + else self = { __proto__: plugins }; plugins.contexts[file.path] = self; plugins[file.path] = self; @@ -203,6 +204,8 @@ const IO = Module("io", { file.append(config.tempFile); file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt('0600', 8)); + Cc["@mozilla.org/uriloader/external-helper-app-service;1"] + .getService(Ci.nsPIExternalAppLauncher).deleteTemporaryFileOnExit(file); return io.File(file); }, @@ -657,12 +660,11 @@ lookup: completion: function () { completion.charset = function (context) { context.anchored = false; - let service = services.get("charset"); context.keys = { text: util.identity, - description: function (charset) service.getCharsetTitle(charset) + description: services.get("charset").getCharsetTitle }; - context.generate = function () iter(service.getDecoderList()); + context.generate = function () iter(services.get("charset").getDecoderList()); }; completion.directory = function directory(context, full) { diff --git a/common/locale/en-US/buffer.xml b/common/locale/en-US/buffer.xml index 155438c0..03c25467 100644 --- a/common/locale/en-US/buffer.xml +++ b/common/locale/en-US/buffer.xml @@ -73,9 +73,7 @@

View source with an external editor. Opens the source code of the current web site with the external editor - specified by the editor option. The external - editor must be able to download and open files from a - remote URL. + specified by the editor option.

diff --git a/common/modules/base.jsm b/common/modules/base.jsm index 3a0fb683..4d482888 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -139,12 +139,11 @@ defineModule("base", { // sed -n 's/^(const|function) ([a-zA-Z0-9_]+).*/ "\2",/p' base.jsm | sort | fmt exports: [ "Cc", "Ci", "Class", "Cr", "Cu", "Module", "Object", "Runnable", - "Struct", "StructBase", "Timer", "UTF8", "XPCOMUtils", "array", + "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMUtils", "array", "call", "callable", "curry", "debuggerProperties", "defineModule", "endModule", "forEach", "isArray", "isGenerator", "isinstance", "isObject", "isString", "isSubclass", "iter", "iterAll", "keys", - "memoize", "properties", "requiresMainThread", "set", "update", - "values" + "memoize", "properties", "requiresMainThread", "set", "update", "values" ], use: ["services"] }); @@ -700,6 +699,25 @@ Class.extend = function extend(subclass, superclass, overrides) { superclass.prototype.constructor = superclass; } +/** + * A base class generator for classes which impliment XPCOM interfaces. + * + * @param {nsIIID|[nsIJSIID]} interfaces The interfaces which the class + * implements. + * @param {Class} superClass A super class. @optional + * @returns {Class} + */ +function XPCOM(interfaces, superClass) { + interfaces = Array.concat(interfaces); + let shim = interfaces.reduce(function (shim, iface) shim.QueryInterface(iface), + Cc["@dactyl.googlecode.com/base/xpc-interface-shim"].createInstance()); + let res = Class("XPCOM(" + interfaces + ")", superClass || Class, update( + array([k, v === undefined || callable(v) ? function stub() null : v] for ([k, v] in Iterator(shim))).toObject(), + { QueryInterface: XPCOMUtils.generateQI(interfaces) })); + shim = interfaces = null; + return res; +} + /** * Memoizes the value of a class property to the falue returned by * the passed function the first time the property is accessed. diff --git a/common/modules/bookmarkcache.jsm b/common/modules/bookmarkcache.jsm index 31301f12..c4586d53 100644 --- a/common/modules/bookmarkcache.jsm +++ b/common/modules/bookmarkcache.jsm @@ -24,7 +24,7 @@ const history = services.get("history"); const tagging = services.get("tagging"); const name = "bookmark-cache"; -const BookmarkCache = Module("BookmarkCache", { +const BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), { init: function init() { bookmarks.addObserver(this, false); }, @@ -116,11 +116,6 @@ const BookmarkCache = Module("BookmarkCache", { return bookmarks; }, - onBeforeItemRemoved: function () {}, - onBeginUpdateBatch: function () {}, - onEndUpdateBatch: function () {}, - onItemVisited: function () {}, - onItemMoved: function () {}, onItemAdded: function onItemAdded(itemId, folder, index) { if (bookmarks.getItemType(itemId) == bookmarks.TYPE_BOOKMARK) { if (this.isBookmark(itemId)) { @@ -147,8 +142,7 @@ const BookmarkCache = Module("BookmarkCache", { storage.fireEvent(name, "change", { __proto__: bookmark, changed: property }); } } - }, - QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver]) + } }, { getFavicon: function getFavicon(uri) { try { diff --git a/common/modules/sanitizer.jsm b/common/modules/sanitizer.jsm index d80ac6a8..40eb96e7 100644 --- a/common/modules/sanitizer.jsm +++ b/common/modules/sanitizer.jsm @@ -29,7 +29,7 @@ Range.prototype.contains = function (date) Range.prototype.__defineGetter__("isEternity", function () this.max == null && this.min == null); Range.prototype.__defineGetter__("isSession", function () this.max == null && this.min == sanitizer.sessionStart); -const Sanitizer = Module("sanitizer", tmp.Sanitizer, { +const Sanitizer = Module("sanitizer", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference], tmp.Sanitizer), { sessionStart: Date.now() * 1000, init: function () { @@ -90,8 +90,6 @@ const Sanitizer = Module("sanitizer", tmp.Sanitizer, { util.addObserver(this); }, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]), - addItem: function addItem(name, params) { if (params.description) this.itemDescriptions[name] = params.description; diff --git a/pentadactyl/TODO b/pentadactyl/TODO index 0325f9c0..07082469 100644 --- a/pentadactyl/TODO +++ b/pentadactyl/TODO @@ -19,7 +19,7 @@ BUGS: - :sidebar improvements (:sidebar! Downloads while downloads is open should refocus the sidebar) - ;s saves the page rather than the image - RC file is sourced once per window -- :undo seems to be effected by the tabstrip state +- :undo seems to be affected by the tabstrip state - the :help version-information page is no longer generated (recent Mercurial regressions):