!import
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1 //@line 37 "/home/visbrero/mnt/roisin/rev_control/hg/mozilla/toolkit/components/viewsource/content/viewSourceUtils.js"
2
3 /*
4 * To keep the global namespace safe, don't define global variables and
5 * functions in this file.
6 *
7 * This file requires contentAreaUtils.js
8 */
9
10 var gViewSourceUtils = {
11
12 mnsIWebBrowserPersist: Components.interfaces.nsIWebBrowserPersist,
13 mnsIWebProgress: Components.interfaces.nsIWebProgress,
14 mnsIWebPageDescriptor: Components.interfaces.nsIWebPageDescriptor,
15
16 // Opens the interval view source viewer
openInInternalViewer
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
17 openInInternalViewer: function(aURL, aPageDescriptor, aDocument)
18 {
19 // try to open a view-source window while inheriting the charset (if any)
20 var charset = null;
21 var isForcedCharset = false;
22 if (aDocument) {
23 charset = "charset=" + aDocument.characterSet;
24 try {
25 isForcedCharset =
26 aDocument.defaultView
27 .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
28 .getInterface(Components.interfaces.nsIDOMWindowUtils)
29 .docCharsetIsForced;
30 } catch (ex) {
31 }
32 }
33 openDialog("chrome://global/content/viewSource.xul",
34 "_blank",
35 "all,dialog=no",
36 aURL, charset, aPageDescriptor, 0, isForcedCharset);
37 },
38
39 // aCallBack is a function accepting two arguments - result (true=success) and a data object
40 // It defaults to openInInternalViewer if undefined.
openInExternalEditor
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
41 openInExternalEditor: function(aURL, aPageDescriptor, aDocument, aCallBack)
42 {
43 var data = {url: aURL, pageDescriptor: aPageDescriptor, doc: aDocument};
44
45 try {
46 var editor = this.getExternalViewSourceEditor();
47 if (!editor) {
48 this.handleCallBack(aCallBack, false, data);
49 return;
50 }
51
52 // make a uri
53 var ios = Components.classes["@mozilla.org/network/io-service;1"]
54 .getService(Components.interfaces.nsIIOService);
55 var charset = aDocument ? aDocument.characterSet : null;
56 var uri = ios.newURI(aURL, charset, null);
57 data.uri = uri;
58
59 var path;
60 var contentType = aDocument ? aDocument.contentType : null;
61 if (uri.scheme == "file") {
62 // it's a local file; we can open it directly
63 path = uri.QueryInterface(Components.interfaces.nsIFileURL).file.path;
64 editor.run(false, [path], 1);
65 this.handleCallBack(aCallBack, true, data);
66 } else {
67 // set up the progress listener with what we know so far
68 this.viewSourceProgressListener.editor = editor;
69 this.viewSourceProgressListener.callBack = aCallBack;
70 this.viewSourceProgressListener.data = data;
71 if (!aPageDescriptor) {
72 // without a page descriptor, loadPage has no chance of working. download the file.
73 var file = this.getTemporaryFile(uri, aDocument, contentType);
74 this.viewSourceProgressListener.file = file;
75
76 var webBrowserPersist = Components
77 .classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
78 .createInstance(this.mnsIWebBrowserPersist);
79 // the default setting is to not decode. we need to decode.
80 webBrowserPersist.persistFlags = this.mnsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
81 webBrowserPersist.progressListener = this.viewSourceProgressListener;
82 webBrowserPersist.saveURI(uri, null, null, null, null, file);
83 } else {
84 // we'll use nsIWebPageDescriptor to get the source because it may not have to refetch
85 // the file from the server
86 var webShell = Components.classes["@mozilla.org/webshell;1"].createInstance();
87 this.viewSourceProgressListener.webShell = webShell;
88 var progress = webShell.QueryInterface(this.mnsIWebProgress);
89 progress.addProgressListener(this.viewSourceProgressListener,
90 this.mnsIWebProgress.NOTIFY_STATE_DOCUMENT);
91 var pageLoader = webShell.QueryInterface(this.mnsIWebPageDescriptor);
92 pageLoader.loadPage(aPageDescriptor, this.mnsIWebPageDescriptor.DISPLAY_AS_SOURCE);
93 }
94 }
95 } catch (ex) {
96 // we failed loading it with the external editor.
97 Components.utils.reportError(ex);
98 this.handleCallBack(aCallBack, false, data);
99 return;
100 }
101 },
102
103 // Default callback - opens the internal viewer if the external editor failed
internalViewerFallback
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
104 internalViewerFallback: function(result, data)
105 {
106 if (!result) {
107 this.openInInternalViewer(data.url, data.pageDescriptor, data.doc);
108 }
109 },
110
111 // Calls the callback, keeping in mind undefined or null values.
handleCallBack
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
112 handleCallBack: function(aCallBack, result, data)
113 {
114 // ifcallback is undefined, default to the internal viewer
115 if (aCallBack === undefined) {
116 this.internalViewerFallback(result, data);
117 } else if (aCallBack) {
118 aCallBack(result, data);
119 }
120 },
121
122 // Returns nsIProcess of the external view source editor or null
getExternalViewSourceEditor
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
123 getExternalViewSourceEditor: function()
124 {
125 var editor = null;
126 var viewSourceAppPath = null;
127 try {
128 var prefs = Components.classes["@mozilla.org/preferences-service;1"]
129 .getService(Components.interfaces.nsIPrefBranch);
130 var prefPath = prefs.getCharPref("view_source.editor.path");
131 if (prefPath.length > 0) {
132 viewSourceAppPath = Components.classes["@mozilla.org/file/local;1"]
133 .createInstance(Components.interfaces.nsILocalFile);
134 viewSourceAppPath.initWithPath(prefPath);
135 // it's gotta be executable
136 if (viewSourceAppPath.exists() && viewSourceAppPath.isExecutable()) {
137 editor = Components.classes['@mozilla.org/process/util;1']
138 .createInstance(Components.interfaces.nsIProcess);
139 editor.init(viewSourceAppPath);
140 }
141 }
142 }
143 catch (ex) {
144 Components.utils.reportError(ex);
145 }
146 return editor;
147 },
148
149 viewSourceProgressListener: {
150
151 mnsIWebProgressListener: Components.interfaces.nsIWebProgressListener,
152
QueryInterface
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
153 QueryInterface: function(aIID) {
154 if (aIID.equals(this.mnsIWebProgressListener) ||
155 aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
156 aIID.equals(Components.interfaces.nsISupports))
157 return this;
158 throw Components.results.NS_NOINTERFACE;
159 },
160
destroy
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
161 destroy: function() {
162 this.webShell = null;
163 this.editor = null;
164 this.callBack = null;
165 this.data = null;
166 this.file = null;
167 },
168
onStateChange
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
169 onStateChange: function(aProgress, aRequest, aFlag, aStatus) {
170 // once it's done loading...
171 if ((aFlag & this.mnsIWebProgressListener.STATE_STOP) && aStatus == 0) {
172 try {
173 if (!this.file) {
174 // it's not saved to file yet, it's in the webshell
175
176 // get a temporary filename using the attributes from the data object that
177 // openInExternalEditor gave us
178 this.file = gViewSourceUtils.getTemporaryFile(this.data.uri, this.data.doc,
179 this.data.doc.contentType);
180
181 // we have to convert from the source charset.
182 var webNavigation = this.webShell.QueryInterface(Components.interfaces.nsIWebNavigation);
183 var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
184 .createInstance(Components.interfaces.nsIFileOutputStream);
185 foStream.init(this.file, 0x02 | 0x08 | 0x20, 0664, 0); // write | create | truncate
186 var coStream = Components.classes["@mozilla.org/intl/converter-output-stream;1"]
187 .createInstance(Components.interfaces.nsIConverterOutputStream);
188 coStream.init(foStream, this.data.doc.characterSet, 0, null);
189
190 // write the source to the file
191 coStream.writeString(webNavigation.document.body.textContent);
192
193 // clean up
194 coStream.close();
195 foStream.close();
196 }
197 // fire up the editor
198 this.editor.run(false, [this.file.path], 1);
199
200 gViewSourceUtils.handleCallBack(this.callBack, true, this.data);
201 } catch (ex) {
202 // we failed loading it with the external editor.
203 Components.utils.reportError(ex);
204 gViewSourceUtils.handleCallBack(this.callBack, false, this.data);
205 } finally {
206 this.destroy();
207 }
208 }
209 return 0;
210 },
211
onLocationChange
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
212 onLocationChange: function() {return 0;},
onProgressChange
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
213 onProgressChange: function() {return 0;},
onStatusChange
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
214 onStatusChange: function() {return 0;},
onSecurityChange
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
215 onSecurityChange: function() {return 0;},
onLinkIconAvailable
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
216 onLinkIconAvailable: function() {return 0;},
217
218 webShell: null,
219 editor: null,
220 callBack: null,
221 data: null,
222 file: null
223 },
224
225 // returns an nsIFile for the passed document in the system temp directory
getTemporaryFile
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
226 getTemporaryFile: function(aURI, aDocument, aContentType) {
227 var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"]
228 .getService(Components.interfaces.nsIProperties);
229 var tempFile = fileLocator.get("TmpD", Components.interfaces.nsIFile);
230 var fileName = getDefaultFileName(null, aURI, aDocument, aContentType);
231 var extension = getDefaultExtension(fileName, aURI, aContentType);
232 var leafName = getNormalizedLeafName(fileName, extension);
233 tempFile.append(leafName);
234 return tempFile;
235 }
236 }