Add generic label mechanism
[conkeror.git] / modules / suggest-file-name.js
blob267cbd398cbf3713b0541ec56a5f1a03ab8e1982
1 /**
2 * (C) Copyright 2007 John J. Foerch
3 * (C) Copyright 2007-2008 Jeremy Maitin-Shepard.
5 * Portions of this file were derived from Mozilla,
6 * (C) Copyright 1998-2007 Mozilla Foundation.
8 * Use, modification, and distribution are subject to the terms specified in the
9 * COPYING file.
10 **/
12 /* maybe_get_filename_extension
14 * file_name_s: string filename, may be null.
16 * returns null or extension part of file_name_s.
18 function maybe_get_filename_extension (file_name_s) {
19 var url = Components.classes["@mozilla.org/network/standard-url;1"]
20 .createInstance(Components.interfaces.nsIURL);
21 url.filePath = file_name_s;
22 if (url.fileExtension == '')
23 return null;
24 return url.fileExtension;
28 function maybe_get_url_extension (url_o) {
29 try {
30 var url = url_o.QueryInterface(Components.interfaces.nsIURL);
31 if (url.fileExtension == '')
32 return null;
33 return url.fileExtension;
34 } catch (e) {
35 return null;
39 /* maybe_get_preferred_filename_extension
41 * file_name_s: string filename, may be null.
43 * content_type: string content type, may be null.
45 * returns null, the default extension for the given
46 * content type, or the extension part of file_name_s.
48 function maybe_get_preferred_filename_extension (file_name_s, content_type)
50 var ext = maybe_get_filename_extension (file_name_s);
51 var mimeInfo = null;
52 var primary = null;
53 if (content_type) {
54 try {
55 // throws if content_type is an empty string
56 mimeInfo = Components.classes["@mozilla.org/mime;1"]
57 .getService(Components.interfaces.nsIMIMEService)
58 .getFromTypeAndExtension(content_type, ext);
59 primary = mimeInfo.primaryExtension;
60 } catch (e) { }
62 if (ext && mimeInfo && mimeInfo.extensionExists (ext))
63 return ext;
64 else if (primary)
65 return primary;
66 else
67 return ext;
71 function maybe_get_preferred_url_extension (url_o, content_type) {
72 var ext = maybe_get_url_extension (url_o);
73 var mimeInfo = null;
74 var primary = null;
75 if (content_type) {
76 try {
77 mimeInfo = Components.classes["@mozilla.org/mime;1"]
78 .getService(Components.interfaces.nsIMIMEService)
79 .getFromTypeAndExtension(content_type, null);
80 primary = mimeInfo.primaryExtension;
81 } catch (e) { }
83 if (ext && mimeInfo && mimeInfo.extensionExists (ext))
84 return ext;
85 else if (primary)
86 return primary;
87 else
88 return ext;
91 function get_default_extension (file_name_s, url_o, content_type) {
92 if (content_type == "text/plain" ||
93 content_type == "application/octet-stream" ||
94 url_o.scheme == "ftp")
96 return "";
98 return (maybe_get_preferred_filename_extension (file_name_s, content_type) ||
99 maybe_get_preferred_url_extension (url_o, content_type));
102 function get_charset_for_save(aDocument)
104 if (aDocument)
105 return aDocument.characterSet;
106 return null;
110 function maybe_filename_from_content_disposition (aContentDisposition, charset) {
111 if (aContentDisposition) {
112 const mhp = Components.classes["@mozilla.org/network/mime-hdrparam;1"]
113 .getService(Components.interfaces.nsIMIMEHeaderParam);
114 var dummy = { value: null }; // Need an out param...
116 var fileName = null;
117 try {
118 fileName = mhp.getParameter(aContentDisposition, "filename", charset, true, dummy);
119 } catch (e) {
120 try {
121 fileName = mhp.getParameter(aContentDisposition, "name", charset, true, dummy);
122 } catch (e) { }
124 if (fileName)
125 return fileName;
126 else
127 return null;
129 return null;
132 function maybe_filename_from_uri(uri) {
133 try {
134 var url = uri.QueryInterface(Components.interfaces.nsIURL);
135 if (url.fileName != "") {
136 // 2) Use the actual file name, if present
137 var textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"].getService(Ci.nsITextToSubURI);
138 return textToSubURI.unEscapeURIForUI(url.originCharset || "UTF-8", url.fileName);
140 } catch (e) {
141 // This is something like a data: and so forth URI... no filename here.
143 return null;
146 function maybe_filename_from_title(title) {
147 if (title) {
148 var docTitle = title.replace(/^\s+|\s+$/g, "");
149 if (docTitle && docTitle.length > 0) {
150 // 3) Use the document title
151 return docTitle;
154 return null;
157 function maybe_filename_from_url_last_directory (aURI) {
158 // 5) If this is a directory, use the last directory name
159 try {
160 var path = aURI.path.match(/\/([^\/]+)\/$/);
161 if (path && path.length > 1)
162 return path[1];
163 return null;
164 } catch (e) {
165 return null;
169 function maybe_filename_from_url_host (aURI) {
170 if (aURI && 'host' in aURI)
171 return aURI.host;
172 return null;
175 function maybe_filename_from_localization_default () {
176 try {
177 return getStringBundle().GetStringFromName("DefaultSaveFileName");
178 } catch (e) {
179 return null;
183 function generate_filename_safely_default (filename) {
184 return filename.replace (/[\/]+/g, '_');
187 function generate_filename_safely_darwin (filename) {
188 return filename.replace(/[\:\/]+/g, '_');
191 function generate_filename_safely_winnt (filename)
193 filename = filename.replace (/[\"]+/g, "'");
194 filename = filename.replace (/[\*\:\?]+/g, ' ');
195 filename = filename.replace (/[\<]+/g, '(');
196 filename = filename.replace (/[\>]+/g, ')');
197 filename = filename.replace (/[\\\/\|]+/g, '_');
198 return filename;
202 var generate_filename_safely_fn = null;
204 switch (get_os()) {
205 case 'Darwin':
206 generate_filename_safely_fn = generate_filename_safely_darwin;
207 break;
208 case 'WINNT':
209 generate_filename_safely_fn = generate_filename_safely_winnt;
210 break;
211 default:
212 generate_filename_safely_fn = generate_filename_safely_default;
213 break;
217 * spec may be a string (URI), a load spec, or an nsIDOMDocument
219 * extension may be null, in which case an extension is suggested as well
221 function suggest_file_name(spec, extension) {
222 var document;
223 var uri;
224 var content_type;
226 if (spec instanceof Ci.nsIDOMDocument)
227 spec = {document: spec};
229 var file_name = load_spec_filename(spec);
231 document = load_spec_document(spec);
232 uri = load_spec_uri(spec);
233 content_type = load_spec_mime_type(spec);
235 if (!file_name) {
236 file_name = generate_filename_safely_fn(
237 maybe_filename_from_content_disposition(document && get_document_content_disposition(document),
238 get_charset_for_save(document)) ||
239 ((spec.suggest_filename_from_uri != false) && maybe_filename_from_uri(uri)) ||
240 maybe_filename_from_title(load_spec_title(spec)) ||
241 maybe_filename_from_url_last_directory(uri) ||
242 maybe_filename_from_url_host(uri) ||
243 maybe_filename_from_localization_default() ||
244 "index");
247 var base_name = file_name.replace(/\.[^.]*$/, "");
249 var file_ext = extension || load_spec_filename_extension(spec);
251 if (!file_ext) {
252 file_ext = get_default_extension(file_name, uri, content_type);
253 if (file_ext == "") {
254 let x = file_name.lastIndexOf(".");
255 if (x == -1)
256 file_ext = null;
257 else
258 file_ext = file_name.substring(x+1);
260 if (!file_ext && (/^http(s?)/i).test(uri.scheme) && !content_type ||
261 content_type == "application/octet-stream")
262 file_ext = "html";
265 if (file_ext != null && file_ext.length > 0)
266 return base_name + "." + file_ext;
267 else
268 return base_name;
271 function suggest_save_path_from_file_name(file_name, buffer) {
272 var cwd = (buffer && buffer.cwd) || default_directory.path;
273 var file = get_file(cwd);
274 file.append(file_name);
275 return file.path;