Prepare the Debian package upload (update release and timestamp in changelog)
[conkeror.git] / modules / content-handler.js
blob5cb6875bdf2e8f2ae7846a5207d7dea5c8bcb858
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 in_module(null);
11 require("mime-type-override.js");
13 define_mime_type_table("content_handlers", {},
14     "A mime type table mapping mime types to content handlers. This table "+
15     "will be checked for a match when a navigation event causes Conkeror "+
16     "to encounter a mime type which is not supported by Mozilla.  If no "+
17     "appropriate content handler is found in this table, the user will "+
18     "be prompted to choose from among common actions.");
20 /**
21  * content_handler_context is a datatype for storing contextual information
22  * that can be used by content handlers, such as window, buffer, frame, and
23  * the download launcher object.  It will also contain an abort method to
24  * abort the download.  Download helper actions are passed an object of this
25  * type.
26  */
27 function content_handler_context (launcher, context) {
28     this.launcher = launcher;
29     try {
30         this.frame = context.QueryInterface(Ci.nsIInterfaceRequestor)
31             .getInterface(Ci.nsIDOMWindowInternal);
32         this.window = get_window_from_frame(this.frame);
33         this.buffer = get_buffer_from_frame(this.frame);
34     } catch (e) {
35         this.window = get_recent_conkeror_window();
36         if (this.window) {
37             this.buffer = this.window.buffers.current;
38             this.frame = this.buffer.focused_frame; //doesn't necessarily exist for all buffer types
39         }
40     }
42 content_handler_context.prototype = {
43     constructor: content_handler_context,
44     launcher: null,
45     window: null,
46     buffer: null,
47     frame: null,
48     abort: function () {
49         const NS_BINDING_ABORTED = 0x804b0002;
50         this.launcher.cancel(NS_BINDING_ABORTED);
51     }
55 /**
56  * The content_handler_* functions below are all things that conkeror
57  * is able to do when Mozilla has invoked download_helper because of an
58  * attempt to navigate to a document of an unsupported mime type.
59  */
60 function content_handler_save (ctx) {
61     var suggested_path = suggest_save_path_from_file_name(
62         ctx.launcher.suggestedFileName, ctx.buffer);
63     var file = yield ctx.window.minibuffer.read_file_check_overwrite(
64         $prompt = "Save to file:",
65         $initial_value = suggested_path,
66         $select);
67     register_download(ctx.buffer, ctx.launcher.source);
68     ctx.launcher.saveToDisk(file, false);
71 function content_handler_save_in (path, inhibit_prompt) {
72     path = make_file(path);
73     return function (ctx) {
74         var file;
75         var suggested_path = path.clone();
76         suggested_path.append(ctx.launcher.suggestedFileName);
77         if (inhibit_prompt)
78             file = suggested_path;
79         else {
80             file = yield ctx.window.minibuffer.read_file_check_overwrite(
81                 $prompt = "Save to file:",
82                 $initial_value = suggested_path.path,
83                 $select);
84         }
85         register_download(ctx.buffer, ctx.launcher.source);
86         ctx.launcher.saveToDisk(file, false);
87     };
90 function content_handler_open (ctx) {
91     var cwd = with_current_buffer(ctx.buffer, function (I) I.local.cwd);
92     var mime_type = ctx.launcher.MIMEInfo.MIMEType;
93     var suggested_action = external_content_handlers.get(mime_type);
94     var command = yield ctx.window.minibuffer.read_shell_command(
95         $initial_value = suggested_action,
96         $cwd = cwd);
97     var file = get_temporary_file(ctx.launcher.suggestedFileName);
98     var info = register_download(ctx.buffer, ctx.launcher.source);
99     info.temporary_status = DOWNLOAD_TEMPORARY_FOR_COMMAND;
100     info.set_shell_command(command, cwd);
101     ctx.launcher.saveToDisk(file, false);
104 function content_handler_open_default_viewer (ctx) {
105     var cwd = with_current_buffer(ctx.buffer, function (I) I.local.cwd);
106     var mime_type = ctx.launcher.MIMEInfo.MIMEType;
107     var command = external_content_handlers.get(mime_type);
108     if (command == null)
109         command = yield ctx.window.minibuffer.read_shell_command(
110             $initial_value = command,
111             $cwd = cwd);
112     var file = get_temporary_file(ctx.launcher.suggestedFileName);
113     var info = register_download(ctx.buffer, ctx.launcher.source);
114     info.temporary_status = DOWNLOAD_TEMPORARY_FOR_COMMAND;
115     info.set_shell_command(command, cwd);
116     ctx.launcher.saveToDisk(file, false);
119 function content_handler_open_url (ctx) {
120     ctx.abort(); // abort download
121     let mime_type = ctx.launcher.MIMEInfo.MIMEType;
122     let cwd = with_current_buffer(ctx.buffer, function (I) I.local.cwd);
123     let cmd = yield ctx.window.minibuffer.read_shell_command(
124         $cwd = cwd,
125         $initial_value = external_content_handlers.get(mime_type));
126     shell_command_with_argument_blind(cmd, ctx.launcher.source.spec, $cwd = cwd);
129 function content_handler_copy_url (ctx) {
130     ctx.abort(); // abort download
131     let uri = ctx.launcher.source.spec;
132     writeToClipboard(uri);
133     ctx.window.minibuffer.message("Copied: " + uri);
136 function content_handler_view_internally (ctx) {
137     var suggested_type = ctx.launcher.MIMEInfo.MIMEType;
138     if (viewable_mime_type_list.indexOf(suggested_type) == -1)
139         suggested_type = "text/plain";
140     var mime_type = yield ctx.window.minibuffer.read_viewable_mime_type(
141         $prompt = "View internally as",
142         $initial_value = suggested_type,
143         $select);
144     ctx.abort(); // abort before reloading
145     override_mime_type_for_next_load(ctx.launcher.source, mime_type);
146     ctx.frame.location = ctx.launcher.source.spec; // reload
149 function content_handler_view_as_text (ctx) {
150     ctx.abort(); // abort before reloading
151     override_mime_type_for_next_load(ctx.launcher.source, "text/plain");
152     ctx.frame.location = ctx.launcher.source.spec; // reload
155 function content_handler_prompt (ctx) {
156     var action_chosen = false;
157     var can_view_internally = ctx.frame != null &&
158         can_override_mime_type_for_uri(ctx.launcher.source);
159     var panel;
160     try {
161         panel = create_info_panel(ctx.window, "download-panel",
162                                   [["downloading", "Downloading:", ctx.launcher.source.spec],
163                                    ["mime-type", "Mime type:", ctx.launcher.MIMEInfo.MIMEType]]);
164         var action = yield ctx.window.minibuffer.read_single_character_option(
165             $prompt = "Action to perform: (s: save; o: open; O: open URL; c: copy URL; " +
166                 (can_view_internally ? "i: view internally; t: view as text)" : ")"),
167             $options = (can_view_internally ? ["s", "o", "O", "c", "i", "t"] : ["s", "o", "O", "c"]));
168         switch (action) {
169         case "s":
170             yield content_handler_save(ctx);
171             action_chosen = true;
172             break;
173         case "o":
174             yield content_handler_open(ctx);
175             action_chosen = true;
176             break;
177         case "O":
178             yield content_handler_open_url(ctx);
179             action_chosen = true;
180             break;
181         case "c":
182             yield content_handler_copy_url(ctx);
183             action_chosen = true;
184             break;
185         case "i":
186             yield content_handler_view_internally(ctx);
187             action_chosen = true;
188             break;
189         case "t":
190             yield content_handler_view_as_text(ctx);
191             action_chosen = true;
192             break;
193         }
194     } catch (e) {
195         handle_interactive_error(ctx.window, e);
196     } finally {
197         if (! action_chosen)
198             ctx.abort();
199         if (panel)
200             panel.destroy();
201     }
206  * download_helper implements nsIHelperAppLauncherDialog.
208  * Sometimes, like when following a link, the content type of the document
209  * cannot be displayed by Mozilla.  When this happens, Mozilla calls the
210  * `show' method of our download_helper with a handle for the started
211  * download and other contextual information.
212  */
213 function download_helper () {}
214 download_helper.prototype = {
215     constructor: download_helper,
216     QueryInterface: generate_QI(Ci.nsIHelperAppLauncherDialog,
217                                 Ci.nsIWebProgressListener2),
218     show: function (launcher, context, reason) {
219         var ctx = new content_handler_context(launcher, context);
220         if (! ctx.window) {
221             ctx.abort(); //XXX: impolite; need better solution.
222             return;
223         }
224         try {
225             // is there anything in content_handlers for this object?
226             var mime_type = launcher.MIMEInfo.MIMEType;
227             var action = content_handlers.get(mime_type) ||
228                 content_handler_prompt;
229             co_call(action(ctx));
230         } catch (e) {
231             handle_interactive_error(ctx.window, e);
232         }
233     },
234     promptForSaveToFile: function (launcher, context, default_file, suggested_file_extension) {
235         return null;
236     }
239 provide("content-handler");