session_save_hist_index renamed to session_save_buffer_access_order
[conkeror.git] / modules / content-handler.js
blobf1a938b107ecd2d04706f3e72ad8720e3b33e52a
1 /**
2  * (C) Copyright 2008 Jeremy Maitin-Shepard
3  * (C) Copyright 2009-2010 John Foerch
4  *
5  * Use, modification, and distribution are subject to the terms specified in the
6  * COPYING file.
7 **/
9 require("mime-type-override.js");
11 define_mime_type_table("content_handlers", {},
12     "A mime type table mapping mime types to content handlers. This table "+
13     "will be checked for a match when a navigation event causes Conkeror "+
14     "to encounter a mime type which is not supported by Mozilla.  If no "+
15     "appropriate content handler is found in this table, the user will "+
16     "be prompted to choose from among common actions.");
18 /**
19  * content_handler_context is a datatype for storing contextual information
20  * that can be used by content handlers, such as window, buffer, frame, and
21  * the download launcher object.  It will also contain an abort method to
22  * abort the download.  Download helper actions are passed an object of this
23  * type.
24  */
25 function content_handler_context (launcher, context) {
26     var xulrunner_version = Cc['@mozilla.org/xre/app-info;1']
27         .getService(Ci.nsIXULAppInfo)
28         .platformVersion;
29     var vc = Cc["@mozilla.org/xpcom/version-comparator;1"]  
30         .getService(Ci.nsIVersionComparator);  
31     this.launcher = launcher;
32     try {
33         this.frame = context.QueryInterface(Ci.nsIInterfaceRequestor)
34             .getInterface((vc.compare(xulrunner_version, "8.0") >= 0) ?
35                           Ci.nsIDOMWindow :
36                           Ci.nsIDOMWindowInternal)
37         this.window = get_window_from_frame(this.frame);
38         this.buffer = get_buffer_from_frame(this.window, this.frame);
39     } catch (e) {
40         dumpln("Error: Failed to find buffer corresponding to content handler context");
41         dump_error(e);
42         this.window = get_recent_conkeror_window();
43         if (this.window) {
44             this.buffer = this.window.buffers.current;
45             this.frame = this.buffer.focused_frame; //doesn't necessarily exist for all buffer types
46         }
47     }
49 content_handler_context.prototype = {
50     constructor: content_handler_context,
51     launcher: null,
52     window: null,
53     buffer: null,
54     frame: null,
55     abort: function () {
56         const NS_BINDING_ABORTED = 0x804b0002;
57         this.launcher.cancel(NS_BINDING_ABORTED);
58     }
62 /**
63  * The content_handler_* functions below are all things that conkeror
64  * is able to do when Mozilla has invoked download_helper because of an
65  * attempt to navigate to a document of an unsupported mime type.
66  */
67 function content_handler_save (ctx) {
68     var suggested_path = suggest_save_path_from_file_name(
69         ctx.launcher.suggestedFileName, ctx.buffer);
70     var file = yield ctx.window.minibuffer.read_file_check_overwrite(
71         $prompt = "Save to file:",
72         $initial_value = suggested_path,
73         $select);
74     register_download(ctx.buffer, ctx.launcher.source);
75     ctx.launcher.saveToDisk(file, false);
78 function content_handler_save_in (path, inhibit_prompt) {
79     path = make_file(path);
80     return function (ctx) {
81         var file;
82         var suggested_path = path.clone();
83         suggested_path.append(ctx.launcher.suggestedFileName);
84         if (inhibit_prompt)
85             file = suggested_path;
86         else {
87             file = yield ctx.window.minibuffer.read_file_check_overwrite(
88                 $prompt = "Save to file:",
89                 $initial_value = suggested_path.path,
90                 $select);
91         }
92         register_download(ctx.buffer, ctx.launcher.source);
93         ctx.launcher.saveToDisk(file, false);
94     };
97 function content_handler_open (ctx) {
98     var cwd = with_current_buffer(ctx.buffer, function (I) I.local.cwd);
99     var mime_type = ctx.launcher.MIMEInfo.MIMEType;
100     var suggested_action = external_content_handlers.get(mime_type);
101     var command = yield ctx.window.minibuffer.read_shell_command(
102         $initial_value = suggested_action,
103         $cwd = cwd);
104     var file = get_temporary_file(ctx.launcher.suggestedFileName);
105     var info = register_download(ctx.buffer, ctx.launcher.source);
106     info.temporary_status = DOWNLOAD_TEMPORARY_FOR_COMMAND;
107     info.set_shell_command(command, cwd);
108     ctx.launcher.saveToDisk(file, false);
111 function content_handler_open_default_viewer (ctx) {
112     var cwd = with_current_buffer(ctx.buffer, function (I) I.local.cwd);
113     var mime_type = ctx.launcher.MIMEInfo.MIMEType;
114     var command = external_content_handlers.get(mime_type);
115     if (command == null)
116         command = yield ctx.window.minibuffer.read_shell_command(
117             $initial_value = command,
118             $cwd = cwd);
119     var file = get_temporary_file(ctx.launcher.suggestedFileName);
120     var info = register_download(ctx.buffer, ctx.launcher.source);
121     info.temporary_status = DOWNLOAD_TEMPORARY_FOR_COMMAND;
122     info.set_shell_command(command, cwd);
123     ctx.launcher.saveToDisk(file, false);
126 function content_handler_open_url (ctx) {
127     ctx.abort(); // abort download
128     let mime_type = ctx.launcher.MIMEInfo.MIMEType;
129     let cwd = with_current_buffer(ctx.buffer, function (I) I.local.cwd);
130     let cmd = yield ctx.window.minibuffer.read_shell_command(
131         $cwd = cwd,
132         $initial_value = external_content_handlers.get(mime_type));
133     shell_command_with_argument_blind(cmd, ctx.launcher.source.spec, $cwd = cwd);
136 function content_handler_copy_url (ctx) {
137     ctx.abort(); // abort download
138     let uri = ctx.launcher.source.spec;
139     writeToClipboard(uri);
140     ctx.window.minibuffer.message("Copied: " + uri);
143 function content_handler_view_internally (ctx) {
144     var suggested_type = ctx.launcher.MIMEInfo.MIMEType;
145     if (viewable_mime_type_list.indexOf(suggested_type) == -1)
146         suggested_type = "text/plain";
147     var mime_type = yield ctx.window.minibuffer.read_viewable_mime_type(
148         $prompt = "View internally as",
149         $initial_value = suggested_type,
150         $select);
151     ctx.abort(); // abort before reloading
152     yield override_mime_type_for_next_load(ctx.launcher.source, mime_type);
153     ctx.frame.location = ctx.launcher.source.spec; // reload
156 function content_handler_view_as_text (ctx) {
157     ctx.abort(); // abort before reloading
158     yield override_mime_type_for_next_load(ctx.launcher.source, "text/plain");
159     ctx.frame.location = ctx.launcher.source.spec; // reload
162 function content_handler_prompt (ctx) {
163     var action_chosen = false;
164     var can_view_internally = ctx.frame != null &&
165         can_override_mime_type_for_uri(ctx.launcher.source);
166     var panel;
167     try {
168         panel = create_info_panel(ctx.window, "download-panel",
169                                   [["downloading", "Downloading:", ctx.launcher.source.spec],
170                                    ["mime-type", "Mime type:", ctx.launcher.MIMEInfo.MIMEType]]);
171         var action = yield ctx.window.minibuffer.read_single_character_option(
172             $prompt = "Action to perform: (s: save; o: open; O: open URL; c: copy URL; " +
173                 (can_view_internally ? "i: view internally; t: view as text)" : ")"),
174             $options = (can_view_internally ? ["s", "o", "O", "c", "i", "t"] : ["s", "o", "O", "c"]));
175         switch (action) {
176         case "s":
177             yield content_handler_save(ctx);
178             action_chosen = true;
179             break;
180         case "o":
181             yield content_handler_open(ctx);
182             action_chosen = true;
183             break;
184         case "O":
185             yield content_handler_open_url(ctx);
186             action_chosen = true;
187             break;
188         case "c":
189             yield content_handler_copy_url(ctx);
190             action_chosen = true;
191             break;
192         case "i":
193             yield content_handler_view_internally(ctx);
194             action_chosen = true;
195             break;
196         case "t":
197             yield content_handler_view_as_text(ctx);
198             action_chosen = true;
199             break;
200         }
201     } catch (e) {
202         handle_interactive_error(ctx.window, e);
203     } finally {
204         if (! action_chosen)
205             ctx.abort();
206         if (panel)
207             panel.destroy();
208     }
213  * download_helper implements nsIHelperAppLauncherDialog.
215  * Sometimes, like when following a link, the content type of the document
216  * cannot be displayed by Mozilla.  When this happens, Mozilla calls the
217  * `show' method of our download_helper with a handle for the started
218  * download and other contextual information.
219  */
220 function download_helper () {}
221 download_helper.prototype = {
222     constructor: download_helper,
223     QueryInterface: generate_QI(Ci.nsIHelperAppLauncherDialog,
224                                 Ci.nsIWebProgressListener2),
225     show: function (launcher, context, reason) {
226         var ctx = new content_handler_context(launcher, context);
227         if (! ctx.window) {
228             dumpln("Warning: Aborting download because of lack of window");
229             ctx.abort(); //XXX: impolite; need better solution.
230             return;
231         }
232         try {
233             // is there anything in content_handlers for this object?
234             var mime_type = launcher.MIMEInfo.MIMEType;
235             var action = content_handlers.get(mime_type) ||
236                 content_handler_prompt;
237             co_call(action(ctx));
238         } catch (e) {
239             handle_interactive_error(ctx.window, e);
240         }
241     },
242     promptForSaveToFile: function (launcher, context, default_file, suggested_file_extension) {
243         return null;
244     }
247 provide("content-handler");