From e3192d032a9205938cfee7fb97e091369913886e Mon Sep 17 00:00:00 2001 From: Henri Sivonen Date: Mon, 12 Dec 2011 10:53:48 +0200 Subject: [PATCH] Bug 700034 - Wait for the view source doc to load before reading its .body.textContent when feeding an external editor. r=gavin.sharp, a=Unfocused. --- .../viewsource/content/viewSourceUtils.js | 121 ++++++++++-------- 1 file changed, 66 insertions(+), 55 deletions(-) diff --git a/toolkit/components/viewsource/content/viewSourceUtils.js b/toolkit/components/viewsource/content/viewSourceUtils.js index 59b7a9182f4..500353eecf8 100644 --- a/toolkit/components/viewsource/content/viewSourceUtils.js +++ b/toolkit/components/viewsource/content/viewSourceUtils.js @@ -226,66 +226,77 @@ var gViewSourceUtils = { onStateChange: function(aProgress, aRequest, aFlag, aStatus) { // once it's done loading... if ((aFlag & this.mnsIWebProgressListener.STATE_STOP) && aStatus == 0) { - try { - if (!this.file) { - // it's not saved to file yet, it's in the webshell - - // get a temporary filename using the attributes from the data object that - // openInExternalEditor gave us - this.file = gViewSourceUtils.getTemporaryFile(this.data.uri, this.data.doc, - this.data.doc.contentType); - - // we have to convert from the source charset. - var webNavigation = this.webShell.QueryInterface(Components.interfaces.nsIWebNavigation); - var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"] - .createInstance(Components.interfaces.nsIFileOutputStream); - foStream.init(this.file, 0x02 | 0x08 | 0x20, 0664, 0); // write | create | truncate - var coStream = Components.classes["@mozilla.org/intl/converter-output-stream;1"] - .createInstance(Components.interfaces.nsIConverterOutputStream); - coStream.init(foStream, this.data.doc.characterSet, 0, null); - - // write the source to the file - coStream.writeString(webNavigation.document.body.textContent); - - // clean up - coStream.close(); - foStream.close(); - - // register the file to be deleted on app exit - Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"] - .getService(Components.interfaces.nsPIExternalAppLauncher) - .deleteTemporaryFileOnExit(this.file); - } - - // Determine the command line arguments to pass to the editor. - // We currently support a %LINE% placeholder which is set to the passed - // line number (or to 0 if there's none) - var editorArgs = []; - var prefs = Components.classes["@mozilla.org/preferences-service;1"] - .getService(Components.interfaces.nsIPrefBranch); - var args = prefs.getCharPref("view_source.editor.args"); - if (args) { - args = args.replace("%LINE%", this.data.lineNumber || "0"); - // add the arguments to the array (keeping quoted strings intact) - const argumentRE = /"([^"]+)"|(\S+)/g; - while (argumentRE.test(args)) - editorArgs.push(RegExp.$1 || RegExp.$2); - } - editorArgs.push(this.file.path); - this.editor.runw(false, editorArgs, editorArgs.length); - - gViewSourceUtils.handleCallBack(this.callBack, true, this.data); - } catch (ex) { - // we failed loading it with the external editor. - Components.utils.reportError(ex); - gViewSourceUtils.handleCallBack(this.callBack, false, this.data); - } finally { - this.destroy(); + var webNavigation = this.webShell.QueryInterface(Components.interfaces.nsIWebNavigation); + if (webNavigation.document.readyState == "complete") { + // This branch is probably never taken. Including it for completeness. + this.onContentLoaded(); + } else { + webNavigation.document.addEventListener("DOMContentLoaded", + this.onContentLoaded.bind(this)); } } return 0; }, + onContentLoaded: function() { + try { + if (!this.file) { + // it's not saved to file yet, it's in the webshell + + // get a temporary filename using the attributes from the data object that + // openInExternalEditor gave us + this.file = gViewSourceUtils.getTemporaryFile(this.data.uri, this.data.doc, + this.data.doc.contentType); + + // we have to convert from the source charset. + var webNavigation = this.webShell.QueryInterface(Components.interfaces.nsIWebNavigation); + var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"] + .createInstance(Components.interfaces.nsIFileOutputStream); + foStream.init(this.file, 0x02 | 0x08 | 0x20, 0664, 0); // write | create | truncate + var coStream = Components.classes["@mozilla.org/intl/converter-output-stream;1"] + .createInstance(Components.interfaces.nsIConverterOutputStream); + coStream.init(foStream, this.data.doc.characterSet, 0, null); + + // write the source to the file + coStream.writeString(webNavigation.document.body.textContent); + + // clean up + coStream.close(); + foStream.close(); + + // register the file to be deleted on app exit + Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"] + .getService(Components.interfaces.nsPIExternalAppLauncher) + .deleteTemporaryFileOnExit(this.file); + } + + // Determine the command line arguments to pass to the editor. + // We currently support a %LINE% placeholder which is set to the passed + // line number (or to 0 if there's none) + var editorArgs = []; + var prefs = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); + var args = prefs.getCharPref("view_source.editor.args"); + if (args) { + args = args.replace("%LINE%", this.data.lineNumber || "0"); + // add the arguments to the array (keeping quoted strings intact) + const argumentRE = /"([^"]+)"|(\S+)/g; + while (argumentRE.test(args)) + editorArgs.push(RegExp.$1 || RegExp.$2); + } + editorArgs.push(this.file.path); + this.editor.runw(false, editorArgs, editorArgs.length); + + gViewSourceUtils.handleCallBack(this.callBack, true, this.data); + } catch (ex) { + // we failed loading it with the external editor. + Components.utils.reportError(ex); + gViewSourceUtils.handleCallBack(this.callBack, false, this.data); + } finally { + this.destroy(); + } + }, + onLocationChange: function() {return 0;}, onProgressChange: function() {return 0;}, onStatusChange: function() {return 0;},