minibuffer-completion.js: Avoid some minor errors
[conkeror.git] / modules / suggest-file-name.js
blob2ab33c55e283ea21ca14998bbf56476476b473df
2 /*
3  *  GENERATE FILENAME
4  */
7 /* maybe_get_filename_extension
8  *
9  * file_name_s: string filename, may be null.
10  *
11  * returns null or extension part of file_name_s.
12  */
13 function maybe_get_filename_extension (file_name_s) {
14     var url = Components.classes["@mozilla.org/network/standard-url;1"]
15         .createInstance(Components.interfaces.nsIURL);
16     url.filePath = file_name_s;
17     if (url.fileExtension == '')
18         return null;
19     return url.fileExtension;
23 function maybe_get_url_extension (url_o) {
24     try {
25         var url = url_o.QueryInterface(Components.interfaces.nsIURL);
26         if (url.fileExtension == '')
27             return null;
28         return url.fileExtension;
29     } catch (e) {
30         return null;
31     }
34 /* maybe_get_preferred_filename_extension
35  *
36  * file_name_s: string filename, may be null.
37  *
38  * content_type: string content type, may be null.
39  *
40  * returns null, the default extension for the given
41  * content type, or the extension part of file_name_s.
42  */
43 function maybe_get_preferred_filename_extension (file_name_s, content_type)
45     var ext = maybe_get_filename_extension (file_name_s);
46     var mimeInfo = null;
47     var primary = null;
48     if (content_type) {
49         try {
50             // throws if content_type is an empty string
51             mimeInfo = Components.classes["@mozilla.org/mime;1"]
52                 .getService(Components.interfaces.nsIMIMEService)
53                 .getFromTypeAndExtension(content_type, ext);
54             primary = mimeInfo.primaryExtension;
55         } catch (e) { }
56     }
57     if (ext && mimeInfo && mimeInfo.extensionExists (ext))
58         return ext;
59     else if (primary)
60         return primary;
61     else
62         return ext;
66 function maybe_get_preferred_url_extension (url_o, content_type) {
67     var ext = maybe_get_url_extension (url_o);
68     var mimeInfo = null;
69     var primary = null;
70     if (content_type) {
71         try {
72             mimeInfo = Components.classes["@mozilla.org/mime;1"]
73                 .getService(Components.interfaces.nsIMIMEService)
74                 .getFromTypeAndExtension(content_type, null);
75             primary = mimeInfo.primaryExtension;
76         } catch (e) { }
77     }
78     if (ext && mimeInfo && mimeInfo.extensionExists (ext))
79         return ext;
80     else if (primary)
81         return primary;
82     else
83         return ext;
86 function get_default_extension (file_name_s, url_o, content_type) {
87     if (content_type == "text/plain" ||
88         content_type == "application/octet-stream" ||
89         url_o.scheme == "ftp")
90     {
91         return "";
92     }
93     return (maybe_get_preferred_filename_extension (file_name_s, content_type) ||
94             maybe_get_preferred_url_extension (url_o, content_type));
97 function get_charset_for_save(aDocument)
99     if (aDocument)
100         return aDocument.characterSet;
101     return null;
105 function maybe_filename_from_content_disposition (aContentDisposition, charset) {
106     if (aContentDisposition) {
107         const mhp = Components.classes["@mozilla.org/network/mime-hdrparam;1"]
108             .getService(Components.interfaces.nsIMIMEHeaderParam);
109         var dummy = { value: null };  // Need an out param...
111         var fileName = null;
112         try {
113             fileName = mhp.getParameter(aContentDisposition, "filename", charset, true, dummy);
114         } catch (e) {
115             try {
116                 fileName = mhp.getParameter(aContentDisposition, "name", charset, true, dummy);
117             } catch (e) { }
118         }
119         if (fileName)
120             return fileName;
121         else
122             return null;
123     }
124     return null;
127 function maybe_filename_from_uri(uri) {
128     try {
129         var url = uri.QueryInterface(Components.interfaces.nsIURL);
130         if (url.fileName != "") {
131             // 2) Use the actual file name, if present
132             var textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"].getService(Ci.nsITextToSubURI);
133             return textToSubURI.unEscapeURIForUI(url.originCharset || "UTF-8", url.fileName);
134         }
135     } catch (e) {
136         // This is something like a data: and so forth URI... no filename here.
137     }
138     return null;
141 function maybe_filename_from_title(title) {
142     if (title) {
143         var docTitle = title.replace(/^\s+|\s+$/g, "");
144         if (docTitle && docTitle.length > 0) {
145             // 3) Use the document title
146             return docTitle;
147         }
148     }
149     return null;
152 function maybe_filename_from_url_last_directory (aURI) {
153     // 5) If this is a directory, use the last directory name
154     try {
155     var path = aURI.path.match(/\/([^\/]+)\/$/);
156     if (path && path.length > 1)
157         return path[1];
158     return null;
159     } catch (e) {
160         return null;
161     }
164 function maybe_filename_from_url_host (aURI) {
165     if (aURI && 'host' in aURI)
166         return aURI.host;
167     return null;
170 function maybe_filename_from_localization_default () {
171     try {
172         return getStringBundle().GetStringFromName("DefaultSaveFileName");
173     } catch (e) {
174         return null;
175     }
178 function generate_filename_safely_default (filename) {
179     return filename.replace (/[\/]+/g, '_');
182 function generate_filename_safely_darwin (filename) {
183     return filename.replace(/[\:\/]+/g, '_');
186 function generate_filename_safely_winnt (filename)
188     filename = filename.replace (/[\"]+/g,     "'");
189     filename = filename.replace (/[\*\:\?]+/g, ' ');
190     filename = filename.replace (/[\<]+/g,     '(');
191     filename = filename.replace (/[\>]+/g,     ')');
192     filename = filename.replace (/[\\\/\|]+/g, '_');
193     return filename;
197 var generate_filename_safely_fn = null;
199 switch (get_os()) {
200 case 'Darwin':
201     generate_filename_safely_fn = generate_filename_safely_darwin;
202     break;
203 case 'WINNT':
204     generate_filename_safely_fn = generate_filename_safely_winnt;
205     break;
206 default:
207     generate_filename_safely_fn = generate_filename_safely_default;
208     break;
212  * spec may be a string (URI), a load spec, or an nsIDOMDocument
214  * extension may be null, in which case an extension is suggested as well
215  */
216 function suggest_file_name(spec, extension) {
217     var document;
218     var uri;
219     var content_type;
221     if (spec instanceof Ci.nsIDOMDocument)
222         spec = {document: spec};
224     var file_name = load_spec_filename(spec);
226     document = load_spec_document(spec);
227     uri = load_spec_uri(spec);
228     content_type = load_spec_mime_type(spec);
230     if (!file_name) {
231         file_name = generate_filename_safely_fn(
232             maybe_filename_from_content_disposition(document && get_document_content_disposition(document),
233                                                     get_charset_for_save(document)) ||
234             ((spec.suggest_filename_from_uri != false) && maybe_filename_from_uri(uri)) ||
235             maybe_filename_from_title(load_spec_title(spec)) ||
236             maybe_filename_from_url_last_directory(uri) ||
237             maybe_filename_from_url_host(uri) ||
238             maybe_filename_from_localization_default() ||
239             "index");
241     }
242     var base_name = file_name.replace(/\.[^.]*$/, "");
244     var file_ext = extension || load_spec_filename_extension(spec);
246     if (!file_ext) {
247         file_ext = get_default_extension(file_name, uri, content_type);
248         if (file_ext == "") {
249             let x = file_name.lastIndexOf(".");
250             if (x == -1)
251                 file_ext = null;
252             else
253                 file_ext = file_name.substring(x+1);
254         }
255         if (!file_ext && (/^http(s?)/i).test(uri.scheme) && !content_type ||
256             content_type == "application/octet-stream")
257             file_ext = "html";
258     }
260     if (file_ext != null && file_ext.length > 0)
261         return base_name + "." + file_ext;
262     else
263         return base_name;
266 function suggest_save_path_from_file_name(file_name, buffer) {
267     var cwd = (buffer && buffer.cwd) || default_directory.path;
268     var file = get_file(cwd);
269     file.append(file_name);
270     return file.path;