gmane page-mode: binding for browser-object-links
[conkeror.git] / modules / load-spec.js
blob29771822a97896e3795eb583614ee87949fe209f
1 /**
2  * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
3  *
4  * Use, modification, and distribution are subject to the terms specified in the
5  * COPYING file.
6 **/
8 /**
9  * A load_spec has the following properties:
10  *
11  * Name:        Required?   Type:           Description:
12  * -----        ---------   -----           ------------
13  * uri          required    string          Specifies the URI of the target.
14  *
15  * document     optional    nsIDOMDocument  Specifies a document corresponding to the target.
16  *                                          Can also provide a default value for the mime_type property,
17  *                                          the title property, and the source_frame property.
18  *
19  * element      optional    nsIDOMNode      The DOM node of a load_spec created by load_spec_from_element.
20  *
21  * flags        optional    number          Specifies flags to pass to nsIWebNavigation.loadURI
22  *
23  * cache_key    optional    nsISHEntry      Specifies a key for accessing the target from the cache.
24  *
25  * referrer     optional    nsIURI          Specifies the referrer URI to use to access the target.
26  *
27  * post_data    optional    nsIInputStream  Specifies POST data to use to access the target.
28  *                                          The request headers should be included in this stream.
29  *
30  * request_mime_type
31  *              optional    string          Specifies the MIME type for the request post data.
32  *
33  * raw_post_data
34  *              optional    nsIInputStream  Specifies the POST data to use to access the target.
35  *                                          The request_mime_type property must also be set.
36  *                                          This provides a value for post_data.
37  *
38  * mime_type    optional    string          Specifies the MIME type of the target.
39  *
40  * title        optional    string          Specifies a title/description text associated with the target.
41  *
42  * source_frame optional    nsIDOMWindow    Specifies the frame from which the link to the target was "obtained".
43  *                                          Can provide a default value for referrer if document is not specified.
44  *
45  * filename     optional    string          Specifies a default filename to use to save the target.
46  *
47  * filename_extension
48  *              optional    string          Specifies a default filename extension to use to save the target.
49  *
50  * suggest_filename_from_uri
51  *              optional    boolean         Specifies whether to attempt to generate a filename from the URI.
52  *                                          Defaults to true.
53  */
55 require("webjump.js");
57 function load_spec_from_element (elem) {
58     var spec = {};
59     if (elem instanceof Ci.nsIDOMWindow)
60         spec.document = elem.document;
62     else if (elem instanceof Ci.nsIDOMHTMLFrameElement ||
63              elem instanceof Ci.nsIDOMHTMLIFrameElement)
64         spec.document = elem.contentDocument;
66     else {
67         var url = null;
68         var title = null;
70         if (elem instanceof Ci.nsIDOMHTMLAnchorElement ||
71             elem instanceof Ci.nsIDOMHTMLAreaElement ||
72             elem instanceof Ci.nsIDOMHTMLLinkElement) {
73             if (elem.hasAttribute("href"))
74                 url = elem.href;
75             title = elem.title || elem.textContent;
76         }
77         else if (elem instanceof Ci.nsIDOMHTMLImageElement) {
78             url = elem.src;
79             title = elem.title || elem.alt;
80         }
81         else {
82             var node = elem;
83             while (node && !(node instanceof Ci.nsIDOMHTMLAnchorElement))
84                 node = node.parentNode;
85             if (node) {
86                 if (node.hasAttribute("href"))
87                     url = node.href;
88                 else
89                     node = null;
90             }
91             if (!node) {
92                 // Try simple XLink
93                 node = elem;
94                 while (node) {
95                     if (node.nodeType == Ci.nsIDOMNode.ELEMENT_NODE) {
96                         url = node.getAttributeNS(XLINK_NS, "href");
97                         break;
98                     }
99                     node = node.parentNode;
100                 }
101                 if (url)
102                     url = makeURLAbsolute(node.baseURI, url);
103                 title = node.title || node.textContent;
104             }
105         }
106         if (url && url.length > 0) {
107             if (title && title.length == 0)
108                 title = null;
109             spec.uri = url;
110             spec.source_frame = elem.ownerDocument.defaultView;
111             spec.title = title;
112         }
113         spec.element = elem;
114     }
115     return spec;
118 function load_spec (x) {
119     var spec;
120     if (typeof(x) == "string")
121         x = get_url_or_webjump(x);
122     if (typeof(x) == "string")
123         spec = { uri: x };
124     else if ((x instanceof Ci.nsIDOMNode) ||
125              (x instanceof Ci.nsIDOMWindow))
126     {
127         spec = load_spec_from_element(x);
128     } else if (typeof(x) == "object") {
129         spec = x;
130     }
131     if (! load_spec_uri_string(spec))
132         throw new Error("Invalid load-spec");
133     spec.__proto__ = load_spec.prototype;
134     return spec;
136 load_spec.prototype = {};
138 function load_spec_document(x) {
139     return x.document;
142 function load_spec_element(x) {
143     return x.element;
146 function load_spec_title(x) {
147     if (x.title)
148         return x.title;
149     if (x.document)
150         return x.document.title;
151     return null;
154 function load_spec_mime_type(x) {
155     if (x.mime_type)
156         return x.mime_type;
157     if (x.document)
158         return x.document.contentType || "application/octet-stream";
159     return mime_type_from_uri(load_spec_uri(x));
162 function load_spec_filename(x) {
163     return x.filename;
166 function load_spec_filename_extension(x) {
167     return x.filename_extension;
170 function get_web_navigation_for_frame(frame) {
171     var ifr = frame.QueryInterface(Ci.nsIInterfaceRequestor);
172     return ifr.getInterface(Ci.nsIWebNavigation);
175 function get_SHEntry_for_document(doc)
177     try
178     {
179         var frame = doc.defaultView;
180         var webNav = get_web_navigation_for_frame(frame);
181         var pageLoader = webNav.QueryInterface(Ci.nsIWebPageDescriptor);
182         var desc = pageLoader.currentDescriptor.QueryInterface(Ci.nsISHEntry);
183         return desc;
184     } catch (e) { return null; }
187 function load_spec_set_properties_from_sh_entry(x) {
188     var sh_entry = get_SHEntry_for_document(x.document);
189     if (sh_entry != null) {
190         x.cache_key = sh_entry;
191         x.referrer = sh_entry.referrerURI;
192         x.post_data = sh_entry.postData;
193     }
196 function load_spec_referrer(x) {
197     if (x.referrer)
198         return x.referrer;
199     if (x.document) {
200         load_spec_set_properties_from_sh_entry(x);
201         return x.referrer;
202     }
203     if (x.source_frame) {
204         x.referrer = x.source_frame.document.documentURIObject;
205         return x.referrer;
206     }
207     return null;
210 function load_spec_post_data(x) {
211     if (x.post_data)
212         return x.post_data;
213     if (x.raw_post_data) {
214         let y = x.raw_post_data;
215         if (typeof(y) == "string")
216             y = string_input_stream(y);
217         x.post_data = mime_input_stream(y, [["Content-Type", x.request_mime_type]]);
218         return x.post_data;
219     }
220     if (x.document) {
221         load_spec_set_properties_from_sh_entry(x);
222         return x.post_data;
223     }
224     return null;
227 function load_spec_raw_post_data(x) {
228     return x.raw_post_data;
231 function load_spec_request_mime_type(x) {
232     return x.request_mime_type;
235 function load_spec_cache_key(x) {
236     if (x.cache_key)
237         return x.cache_key;
238     if (x.document) {
239         load_spec_set_properties_from_sh_entry(x);
240         return x.cache_key;
241     }
242     return null;
245 function load_spec_source_frame(x) {
246     if (x.source_frame)
247         return x.source_frame;
248     if (x.document)
249         return x.document.defaultView;
250     return null;
253 function load_spec_uri_string(x) {
254     if (x.uri)
255         return x.uri;
256     if (x.document && x.document.defaultView)
257         return x.document.defaultView.location.href;
258     if (x.document)
259         return x.document.documentURI;
260     return null;
263 function load_spec_uri(x) {
264     if (x.document && x.document.defaultView)
265         return make_uri(x.document.defaultView.location.href);
266     if (x.document)
267         return x.document.documentURIObject;
268     return make_uri(load_spec_uri_string(x));
271 function load_spec_flags(x) {
272     return x.load_spec_flags;
275 function load_spec_mime_info(x) {
276     var type = load_spec_mime_type(x);
277     return mime_info_from_mime_type(type);
280 function load_spec_default_shell_command(x) {
281     var mime_type = load_spec_mime_type(x);
282     return get_mime_type_external_handler(mime_type);
285 function load_spec_forced_charset (x) {
286     return x.forced_charset;
289 define_variable('forced_charset_list', null,
290     "Alist mapping url-regexps to forced charsets.  The first match "+
291     "will be used.");
293 /* Target can be either a content_buffer or an nsIWebNavigation */
294 function apply_load_spec(target, spec) {
295     if (! (spec instanceof load_spec))
296         spec = load_spec(spec);
297     var uri = load_spec_uri_string(spec);
298     var flags = load_spec_flags(spec);
299     var referrer = load_spec_referrer(spec);
300     var post_data = load_spec_post_data(spec);
301     var forced_charset = load_spec_forced_charset(spec);
303     if (! forced_charset && forced_charset_list)
304         forced_charset = predicate_alist_match(forced_charset_list, uri);
306     if (forced_charset) {
307         try {
308             var atomservice = Cc['@mozilla.org/atom-service;1']
309                 .getService(Ci.nsIAtomService);
310             target.web_navigation.documentCharsetInfo.forcedCharset =
311                 atomservice.getAtom(forced_charset);
312         } catch (e) {}
313     }
315     if (flags == null)
316         flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
318     if (target instanceof content_buffer) {
319         try {
320             target.web_navigation.loadURI(uri, flags, referrer, post_data, null /* headers */);
321             target._display_URI = uri;
322             buffer_description_change_hook.run(target);
323         } catch (e) {
324             /* Ignore error for now */
325         }
326     } else {
327         try {
328             target.loadURI(uri, flags, referrer, post_data, null /* headers */);
329         } catch (e) {
330             /* Ignore error for now */
331         }
332     }