2 * (C) Copyright 2008 Jeremy Maitin-Shepard
3 * (C) Copyright 2009-2010 John Foerch
5 * Use, modification, and distribution are subject to the terms specified in the
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.");
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
27 function content_handler_context () {}
31 * The content_handler_* functions below are all things that conkeror
32 * is able to do when Mozilla has invoked download_helper because of an
33 * attempt to navigate to a document of an unsupported mime type.
35 function content_handler_save (ctx) {
36 var suggested_path = suggest_save_path_from_file_name(
37 ctx.launcher.suggestedFileName, ctx.buffer);
38 var file = yield ctx.window.minibuffer.read_file_check_overwrite(
39 $prompt = "Save to file:",
40 $initial_value = suggested_path,
42 register_download(ctx.buffer, ctx.launcher.source);
43 ctx.launcher.saveToDisk(file, false);
46 function content_handler_save_in (path, inhibit_prompt) {
47 path = make_file(path);
48 return function (ctx) {
50 var suggested_path = path.clone();
51 suggested_path.append(ctx.launcher.suggestedFileName);
53 file = suggested_path;
55 file = yield ctx.window.minibuffer.read_file_check_overwrite(
56 $prompt = "Save to file:",
57 $initial_value = suggested_path.path,
60 register_download(ctx.buffer, ctx.launcher.source);
61 ctx.launcher.saveToDisk(file, false);
65 function content_handler_open (ctx) {
66 var cwd = with_current_buffer(ctx.buffer, function (I) I.local.cwd);
67 var mime_type = ctx.launcher.MIMEInfo.MIMEType;
68 var suggested_action = external_content_handlers.get(mime_type);
69 var command = yield ctx.window.minibuffer.read_shell_command(
70 $initial_value = suggested_action,
72 var file = get_temporary_file(ctx.launcher.suggestedFileName);
73 var info = register_download(ctx.buffer, ctx.launcher.source);
74 info.temporary_status = DOWNLOAD_TEMPORARY_FOR_COMMAND;
75 info.set_shell_command(command, cwd);
76 ctx.launcher.saveToDisk(file, false);
79 function content_handler_open_default_viewer (ctx) {
80 var cwd = with_current_buffer(ctx.buffer, function (I) I.local.cwd);
81 var mime_type = ctx.launcher.MIMEInfo.MIMEType;
82 var command = external_content_handlers.get(mime_type);
84 command = yield ctx.window.minibuffer.read_shell_command(
85 $initial_value = command,
87 var file = get_temporary_file(ctx.launcher.suggestedFileName);
88 var info = register_download(ctx.buffer, ctx.launcher.source);
89 info.temporary_status = DOWNLOAD_TEMPORARY_FOR_COMMAND;
90 info.set_shell_command(command, cwd);
91 ctx.launcher.saveToDisk(file, false);
94 function content_handler_open_url (ctx) {
95 ctx.abort(); // abort download
96 let mime_type = ctx.launcher.MIMEInfo.MIMEType;
97 let cwd = with_current_buffer(ctx.buffer, function (I) I.local.cwd);
98 let cmd = yield ctx.window.minibuffer.read_shell_command(
100 $initial_value = external_content_handlers.get(mime_type));
101 shell_command_with_argument_blind(cmd, ctx.launcher.source.spec, $cwd = cwd);
104 function content_handler_copy_url (ctx) {
105 ctx.abort(); // abort download
106 let uri = ctx.launcher.source.spec;
107 writeToClipboard(uri);
108 ctx.window.minibuffer.message("Copied: " + uri);
111 function content_handler_view_internally (ctx) {
112 var suggested_type = ctx.launcher.MIMEInfo.MIMEType;
113 if (viewable_mime_type_list.indexOf(suggested_type) == -1)
114 suggested_type = "text/plain";
115 var mime_type = yield ctx.window.minibuffer.read_viewable_mime_type(
116 $prompt = "View internally as",
117 $initial_value = suggested_type,
119 ctx.abort(); // abort before reloading
120 override_mime_type_for_next_load(ctx.launcher.source, mime_type);
121 ctx.frame.location = ctx.launcher.source.spec; // reload
124 function content_handler_view_as_text (ctx) {
125 ctx.abort(); // abort before reloading
126 override_mime_type_for_next_load(ctx.launcher.source, "text/plain");
127 ctx.frame.location = ctx.launcher.source.spec; // reload
130 function content_handler_prompt (ctx) {
131 var action_chosen = false;
132 var can_view_internally = ctx.frame != null &&
133 can_override_mime_type_for_uri(ctx.launcher.source);
136 panel = create_info_panel(ctx.window, "download-panel",
137 [["downloading", "Downloading:", ctx.launcher.source.spec],
138 ["mime-type", "Mime type:", ctx.launcher.MIMEInfo.MIMEType]]);
139 var action = yield ctx.window.minibuffer.read_single_character_option(
140 $prompt = "Action to perform: (s: save; o: open; O: open URL; c: copy URL; " +
141 (can_view_internally ? "i: view internally; t: view as text)" : ")"),
142 $options = (can_view_internally ? ["s", "o", "O", "c", "i", "t"] : ["s", "o", "O", "c"]));
145 yield content_handler_save(ctx);
146 action_chosen = true;
149 yield content_handler_open(ctx);
150 action_chosen = true;
153 yield content_handler_open_url(ctx);
154 action_chosen = true;
157 yield content_handler_copy_url(ctx);
158 action_chosen = true;
161 yield content_handler_view_internally(ctx);
162 action_chosen = true;
165 yield content_handler_view_as_text(ctx);
166 action_chosen = true;
170 handle_interactive_error(ctx.window, e);
181 * download_helper implements nsIHelperAppLauncherDialog.
183 * Sometimes, like when following a link, the content type of the document
184 * cannot be displayed by Mozilla. When this happens, Mozilla calls the
185 * `show' method of our download_helper with a handle for the started
186 * download and other contextual information.
188 function download_helper () {}
189 download_helper.prototype = {
190 constructor: download_helper,
191 QueryInterface: generate_QI(Ci.nsIHelperAppLauncherDialog,
192 Ci.nsIWebProgressListener2),
194 show: function (launcher, context, reason) {
195 // content handlers will be passed a context containing references
196 // to the window, buffer, frame, launcher, and an abort method.
197 var ctx = new content_handler_context();
198 ctx.launcher = launcher;
199 ctx.abort = function () {
200 const NS_BINDING_ABORTED = 0x804b0002;
201 launcher.cancel(NS_BINDING_ABORTED);
203 // then set frame, window, and buffer in the context, so that
204 // action handlers can use them if needed.
206 ctx.frame = context.QueryInterface(Ci.nsIInterfaceRequestor)
207 .getInterface(Ci.nsIDOMWindowInternal);
208 ctx.window = get_window_from_frame(ctx.frame);
209 ctx.buffer = get_buffer_from_frame(ctx.window, ctx.frame);
211 ctx.window = get_recent_conkeror_window();
213 // FIXME: need to handle this case perhaps where no windows exist
214 ctx.abort(); // for now, just cancel the download
217 ctx.buffer = ctx.window.buffers.current;
218 ctx.frame = ctx.buffer.focused_frame;
221 // is there anything in content_handlers for this object?
222 var mime_type = launcher.MIMEInfo.MIMEType;
223 var action = content_handlers.get(mime_type) ||
224 content_handler_prompt;
225 co_call(action(ctx));
227 handle_interactive_error(ctx.window, e);
231 promptForSaveToFile: function (launcher, context, default_file, suggested_file_extension) {
236 provide("content-handler");