allow docstrings for global-modes and window-modes
[conkeror/arlinius.git] / modules / suggest-file-name.js
blob6edeae128aa008a4c36cf10604d04d2ddd6bd90c
1 /**
2  * (C) Copyright 2007,2010 John J. Foerch
3  * (C) Copyright 2007-2008 Jeremy Maitin-Shepard.
4  *
5  * Portions of this file were derived from Mozilla,
6  * (C) Copyright 1998-2007 Mozilla Foundation.
7  *
8  * Use, modification, and distribution are subject to the terms specified in the
9  * COPYING file.
10 **/
12 /**
13  * maybe_get_filename_extension
14  *
15  * file_name_s: string filename, may be null.
16  *
17  * returns null or extension part of file_name_s.
18  */
19 function maybe_get_filename_extension (file_name_s) {
20     var url = Cc["@mozilla.org/network/standard-url;1"]
21         .createInstance(Ci.nsIURL);
22     url.filePath = file_name_s;
23     if (url.fileExtension == '')
24         return null;
25     return url.fileExtension;
29 function maybe_get_url_extension (url_o) {
30     try {
31         var url = url_o.QueryInterface(Ci.nsIURL);
32         if (url.fileExtension == '')
33             return null;
34         return url.fileExtension;
35     } catch (e) {
36         return null;
37     }
40 /**
41  * maybe_get_preferred_filename_extension
42  *
43  * file_name_s: string filename, may be null.
44  *
45  * content_type: string content type, may be null.
46  *
47  * returns null, the default extension for the given
48  * content type, or the extension part of file_name_s.
49  */
50 function maybe_get_preferred_filename_extension (file_name_s, content_type) {
51     var ext = maybe_get_filename_extension (file_name_s);
52     var mimeInfo = null;
53     var primary = null;
54     if (content_type) {
55         try {
56             // throws if content_type is an empty string
57             mimeInfo = Cc["@mozilla.org/mime;1"]
58                 .getService(Ci.nsIMIMEService)
59                 .getFromTypeAndExtension(content_type, ext);
60             primary = mimeInfo.primaryExtension;
61         } catch (e) { }
62     }
63     if (ext && mimeInfo && mimeInfo.extensionExists(ext))
64         return ext;
65     else if (primary)
66         return primary;
67     else
68         return ext;
72 function maybe_get_preferred_url_extension (url_o, content_type) {
73     var ext = maybe_get_url_extension(url_o);
74     var mimeInfo = null;
75     var primary = null;
76     if (content_type) {
77         try {
78             mimeInfo = Cc["@mozilla.org/mime;1"]
79                 .getService(Ci.nsIMIMEService)
80                 .getFromTypeAndExtension(content_type, null);
81             primary = mimeInfo.primaryExtension;
82         } catch (e) { }
83     }
84     if (ext && mimeInfo && mimeInfo.extensionExists(ext))
85         return ext;
86     else if (primary)
87         return primary;
88     else
89         return ext;
92 function get_default_extension (file_name_s, url_o, content_type) {
93     if (content_type == "text/plain" ||
94         content_type == "application/octet-stream" ||
95         url_o.scheme == "ftp")
96     {
97         return "";
98     }
99     return (maybe_get_preferred_filename_extension(file_name_s, content_type) ||
100             maybe_get_preferred_url_extension(url_o, content_type));
103 function get_charset_for_save (doc) {
104     if (doc)
105         return doc.characterSet;
106     return null;
109 function maybe_filename_from_content_disposition (spec) {
110     var document = load_spec_document(spec);
111     var content_disposition = (document && get_document_content_disposition(document));
112     var charset = get_charset_for_save(document);
113     if (content_disposition) {
114         const mhp = Cc["@mozilla.org/network/mime-hdrparam;1"]
115             .getService(Ci.nsIMIMEHeaderParam);
116         var dummy = { value: null };  // Need an out param...
118         var filename = null;
119         try {
120             filename = mhp.getParameter(content_disposition, "filename", charset, true, dummy);
121         } catch (e) {
122             try {
123                 filename = mhp.getParameter(content_disposition, "name", charset, true, dummy);
124             } catch (e) { }
125         }
126         if (filename)
127             return filename;
128         else
129             return null;
130     }
131     return null;
134 function maybe_filename_from_uri (spec) {
135     var uri = load_spec_uri(spec);
136     try {
137         var url = uri.QueryInterface(Ci.nsIURL);
138         if (url.fileName != "") {
139             // 2) Use the actual file name, if present
140             var text_to_sub_uri = Cc["@mozilla.org/intl/texttosuburi;1"].
141                 getService(Ci.nsITextToSubURI);
142             return text_to_sub_uri.unEscapeURIForUI(url.originCharset ||
143                                                     "UTF-8", url.fileName);
144         }
145     } catch (e) {
146         // This is something like a data: and so forth URI... no filename here.
147     }
148     return null;
152  * maybe_filename_from_title returns a filename from the load-spec's title
153  * property if and only if the load-spec has neither a document nor an
154  * element property.  In those cases, defer to generating the filename
155  * from the uri.
156  */
157 function maybe_filename_from_title (spec) {
158     if (load_spec_document(spec) || load_spec_element(spec))
159         return null;
160     var title = load_spec_title(spec);
161     if (title) {
162         title = trim_whitespace(title);
163         if (title)
164             return title + ".";
165     }
166     return null;
169 function maybe_filename_from_url_last_directory (spec) {
170     var uri = load_spec_uri(spec);
171     try {
172         var path = uri.path.match(/\/([^\/]+)\/$/);
173         if (path && path.length > 1)
174             return path[1] + ".";
175         return null;
176     } catch (e) {
177         return null;
178     }
181 function maybe_filename_from_url_host (spec) {
182     var uri = load_spec_uri(spec);
183     if (uri && 'host' in uri) {
184         try {
185             return uri.host + ".";
186         } catch (e) {}
187     }
188     return null;
191 function maybe_filename_from_localization_default () {
192     try {
193         return getStringBundle().GetStringFromName("DefaultSaveFileName");
194     } catch (e) {
195         return null;
196     }
201  * Sanitize filename for various platforms.
202  */
204 function generate_filename_safely_default (filename) {
205     return filename.replace(/[\/]+/g, '_');
208 function generate_filename_safely_darwin (filename) {
209     return filename.replace(/[\:\/]+/g, '_');
212 function generate_filename_safely_winnt (filename) {
213     filename = filename.replace(/[\"]+/g,     "'");
214     filename = filename.replace(/[\*\:\?]+/g, ' ');
215     filename = filename.replace(/[\<]+/g,     '(');
216     filename = filename.replace(/[\>]+/g,     ')');
217     filename = filename.replace(/[\\\/\|]+/g, '_');
218     return filename;
222 define_variable("generate_filename_safely_fn",
223     ({ Darwin: generate_filename_safely_darwin,
224        WINNT: generate_filename_safely_winnt }[get_os()]
225      || generate_filename_safely_default),
226     "Function to sanitize the filenames generated by suggest_file_name "+
227     "for the current platform.");
231  * spec may be a string (URI), a load spec, or an nsIDOMDocument
233  * extension may be null, in which case an extension is suggested as well
234  */
235 function suggest_file_name (spec, extension) {
236     if (typeof spec == "string" || spec instanceof Ci.nsIDOMDocument)
237         spec = load_spec(spec);
239     var file_name = load_spec_filename(spec);
240     var uri = load_spec_uri(spec);
241     var content_type = load_spec_mime_type(spec);
243     if (! file_name) {
244         file_name = generate_filename_safely_fn(
245             maybe_filename_from_content_disposition(spec) ||
246             maybe_filename_from_title(spec) ||
247             maybe_filename_from_uri(spec) ||
248             maybe_filename_from_url_last_directory(spec) ||
249             maybe_filename_from_url_host(spec) ||
250             maybe_filename_from_localization_default() ||
251             "index");
252     }
253     var base_name = file_name.replace(/\.[^.]*$/, "");
255     var file_ext = extension || load_spec_filename_extension(spec);
257     if (! file_ext) {
258         file_ext = get_default_extension(file_name, uri, content_type);
259         if (file_ext == "") {
260             let x = file_name.lastIndexOf(".");
261             if (x == -1)
262                 file_ext = null;
263             else
264                 file_ext = file_name.substring(x+1);
265         }
266         if (!file_ext && (/^http(s?)/i).test(uri.scheme) && !content_type ||
267             content_type == "application/octet-stream")
268         {
269             file_ext = "html";
270         }
271     }
273     if (file_ext != null && file_ext.length > 0)
274         return base_name + "." + file_ext;
275     else
276         return base_name;
279 function suggest_save_path_from_file_name (file_name, buffer) {
280     var cwd = with_current_buffer(buffer, function (I) I.local.cwd);
281     var file = cwd.clone();
282     file.append(file_name);
283     return file.path;
286 provide("suggest-file-name");