call_on_focused_field, modify_region: support richedit frames
[conkeror.git] / modules / load-spec.js
blob56fc48134de5a1c45d1871572700766ff93799f3
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 in_module(null);
57 require("webjump.js");
59 function page_fragment_load_spec (elem) {
60     var uri = makeURLAbsolute(elem.ownerDocument.documentURI,
61                               "#" + (elem.id || elem.name));
62     var title = elem.ownerDocument.title;
63     if (elem.textContent) {
64         if (title) title += ' - ';
65         title += elem.textContent;
66     }
67     return {
68         uri: uri,
69         element: elem,
70         title: title
71     };
74 function load_spec_from_element (elem) {
75     var spec = {};
76     if (elem instanceof Ci.nsIDOMWindow)
77         spec.document = elem.document;
79     else if (elem instanceof Ci.nsIDOMHTMLFrameElement ||
80              elem instanceof Ci.nsIDOMHTMLIFrameElement)
81         spec.document = elem.contentDocument;
83     else {
84         var url = null;
85         var title = null;
87         if ((elem instanceof Ci.nsIDOMHTMLAnchorElement ||
88              elem instanceof Ci.nsIDOMHTMLAreaElement ||
89              elem instanceof Ci.nsIDOMHTMLLinkElement) &&
90             elem.hasAttribute("href"))
91         {
92             url = elem.href;
93             title = elem.title || elem.textContent;
94         }
95         else if (elem instanceof Ci.nsIDOMHTMLImageElement) {
96             url = elem.src;
97             title = elem.title || elem.alt;
98         }
99         else if (elem.hasAttribute("id") ||
100                  (elem instanceof Ci.nsIDOMHTMLAnchorElement &&
101                   elem.hasAttribute("name"))) {
102             return page_fragment_load_spec(elem);
103         }
104         else {
105             var node = elem;
106             while (node && !(node instanceof Ci.nsIDOMHTMLAnchorElement))
107                 node = node.parentNode;
108             if (node) {
109                 if (node.hasAttribute("href"))
110                     url = node.href;
111                 else
112                     node = null;
113             }
114             if (!node) {
115                 // Try simple XLink
116                 node = elem;
117                 while (node) {
118                     if (node.nodeType == Ci.nsIDOMNode.ELEMENT_NODE) {
119                         url = node.getAttributeNS(XLINK_NS, "href");
120                         break;
121                     }
122                     node = node.parentNode;
123                 }
124                 if (url)
125                     url = makeURLAbsolute(node.baseURI, url);
126                 title = node.title || node.textContent;
127             }
128         }
129         if (url && url.length > 0) {
130             if (title && title.length == 0)
131                 title = null;
132             spec.uri = url;
133             spec.source_frame = elem.ownerDocument.defaultView;
134             spec.title = title;
135         }
136         spec.element = elem;
137     }
138     return spec;
141 function load_spec (x) {
142     var spec;
143     if (typeof(x) == "string")
144         x = get_url_or_webjump(x);
145     if (typeof(x) == "string")
146         spec = { uri: x };
147     else if ((x instanceof Ci.nsIDOMNode) ||
148              (x instanceof Ci.nsIDOMWindow))
149     {
150         spec = load_spec_from_element(x);
151     } else if (typeof(x) == "object") {
152         spec = x;
153     }
154     if (! load_spec_uri_string(spec))
155         throw new Error("Invalid load-spec");
156     spec.__proto__ = load_spec.prototype;
157     return spec;
159 load_spec.prototype = {
160     constructor: load_spec,
161     toString: function () "[object load_spec]"
164 function load_spec_document (x) {
165     return x.document;
168 function load_spec_element (x) {
169     return x.element;
172 function load_spec_title (x) {
173     if (x.title)
174         return x.title;
175     if (x.document)
176         return x.document.title;
177     return null;
180 function load_spec_mime_type (x) {
181     if (x.mime_type)
182         return x.mime_type;
183     if (x.document)
184         return x.document.contentType || "application/octet-stream";
185     return mime_type_from_uri(load_spec_uri(x));
188 function load_spec_filename (x) {
189     return x.filename;
192 function load_spec_filename_extension (x) {
193     return x.filename_extension;
196 function get_web_navigation_for_frame (frame) {
197     var ifr = frame.QueryInterface(Ci.nsIInterfaceRequestor);
198     return ifr.getInterface(Ci.nsIWebNavigation);
201 function get_SHEntry_for_document (doc) {
202     try {
203         var frame = doc.defaultView;
204         var webNav = get_web_navigation_for_frame(frame);
205         var pageLoader = webNav.QueryInterface(Ci.nsIWebPageDescriptor);
206         var desc = pageLoader.currentDescriptor.QueryInterface(Ci.nsISHEntry);
207         return desc;
208     } catch (e) { return null; }
211 function load_spec_set_properties_from_sh_entry (x) {
212     var sh_entry = get_SHEntry_for_document(x.document);
213     if (sh_entry != null) {
214         x.cache_key = sh_entry;
215         x.referrer = sh_entry.referrerURI;
216         x.post_data = sh_entry.postData;
217     }
220 function load_spec_referrer (x) {
221     if (x.referrer)
222         return x.referrer;
223     if (x.document) {
224         load_spec_set_properties_from_sh_entry(x);
225         return x.referrer;
226     }
227     if (x.source_frame) {
228         x.referrer = x.source_frame.document.documentURIObject;
229         return x.referrer;
230     }
231     return null;
234 function load_spec_post_data (x) {
235     if (x.post_data)
236         return x.post_data;
237     if (x.raw_post_data) {
238         let y = x.raw_post_data;
239         if (typeof(y) == "string")
240             y = string_input_stream(y);
241         x.post_data = mime_input_stream(y, [["Content-Type", x.request_mime_type]]);
242         return x.post_data;
243     }
244     if (x.document) {
245         load_spec_set_properties_from_sh_entry(x);
246         return x.post_data;
247     }
248     return null;
251 function load_spec_raw_post_data (x) {
252     return x.raw_post_data;
255 function load_spec_request_mime_type (x) {
256     return x.request_mime_type;
259 function load_spec_cache_key (x) {
260     if (x.cache_key)
261         return x.cache_key;
262     if (x.document) {
263         load_spec_set_properties_from_sh_entry(x);
264         return x.cache_key;
265     }
266     return null;
269 function load_spec_source_frame (x) {
270     if (x.source_frame)
271         return x.source_frame;
272     if (x.document)
273         return x.document.defaultView;
274     return null;
277 function load_spec_uri_string (x) {
278     if (x.uri)
279         return x.uri;
280     if (x.document && x.document.defaultView)
281         return x.document.defaultView.location.href;
282     if (x.document)
283         return x.document.documentURI;
284     return null;
287 function load_spec_uri (x) {
288     if (x.document && x.document.defaultView)
289         return make_uri(x.document.defaultView.location.href);
290     if (x.document)
291         return x.document.documentURIObject;
292     return make_uri(load_spec_uri_string(x));
295 function load_spec_flags (x) {
296     return x.load_spec_flags;
299 function load_spec_mime_info (x) {
300     var type = load_spec_mime_type(x);
301     return mime_info_from_mime_type(type);
304 function load_spec_default_shell_command (x) {
305     var mime_type = load_spec_mime_type(x);
306     return external_content_handlers.get(mime_type);
309 function load_spec_forced_charset (x) {
310     return x.forced_charset;
313 define_variable('forced_charset_list', null,
314     "Alist mapping url-regexps to forced charsets.  The first match "+
315     "will be used.");
317 /* Target can be either a content_buffer or an nsIWebNavigation */
318 function apply_load_spec (target, spec) {
319     if (! (spec instanceof load_spec))
320         spec = load_spec(spec);
321     var uri = load_spec_uri_string(spec);
322     var flags = load_spec_flags(spec);
323     var referrer = load_spec_referrer(spec);
324     var post_data = load_spec_post_data(spec);
325     var forced_charset = load_spec_forced_charset(spec);
327     if (! forced_charset && forced_charset_list)
328         forced_charset = predicate_alist_match(forced_charset_list, uri);
330     if (forced_charset) {
331         try {
332             var atomservice = Cc['@mozilla.org/atom-service;1']
333                 .getService(Ci.nsIAtomService);
334             target.web_navigation.documentCharsetInfo.forcedCharset =
335                 atomservice.getAtom(forced_charset);
336         } catch (e) {}
337     }
339     if (flags == null)
340         flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
342     if (target instanceof content_buffer) {
343         try {
344             target.web_navigation.loadURI(uri, flags, referrer, post_data, null /* headers */);
345             target._display_uri = uri;
346             buffer_description_change_hook.run(target);
347         } catch (e) {
348             /* Ignore error for now */
349         }
350     } else {
351         try {
352             target.loadURI(uri, flags, referrer, post_data, null /* headers */);
353         } catch (e) {
354             /* Ignore error for now */
355         }
356     }
359 provide("load-spec");