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
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.");
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
25 function content_handler_context (launcher
, context
) {
26 var xulrunner_version
= Cc
['@mozilla.org/xre/app-info;1']
27 .getService(Ci
.nsIXULAppInfo
)
29 var vc
= Cc
["@mozilla.org/xpcom/version-comparator;1"]
30 .getService(Ci
.nsIVersionComparator
);
31 this.launcher
= launcher
;
33 this.frame
= context
.QueryInterface(Ci
.nsIInterfaceRequestor
)
34 .getInterface((vc
.compare(xulrunner_version
, "8.0") >= 0) ?
36 Ci
.nsIDOMWindowInternal
)
37 this.window
= get_window_from_frame(this.frame
);
38 this.buffer
= get_buffer_from_frame(this.frame
);
40 this.window
= get_recent_conkeror_window();
42 this.buffer
= this.window
.buffers
.current
;
43 this.frame
= this.buffer
.focused_frame
; //doesn't necessarily exist for all buffer types
47 content_handler_context
.prototype = {
48 constructor: content_handler_context
,
54 const NS_BINDING_ABORTED
= 0x804b0002;
55 this.launcher
.cancel(NS_BINDING_ABORTED
);
61 * The content_handler_* functions below are all things that conkeror
62 * is able to do when Mozilla has invoked download_helper because of an
63 * attempt to navigate to a document of an unsupported mime type.
65 function content_handler_save (ctx
) {
66 var suggested_path
= suggest_save_path_from_file_name(
67 ctx
.launcher
.suggestedFileName
, ctx
.buffer
);
68 var file
= yield ctx
.window
.minibuffer
.read_file_check_overwrite(
69 $prompt
= "Save to file:",
70 $initial_value
= suggested_path
,
72 register_download(ctx
.buffer
, ctx
.launcher
.source
);
73 ctx
.launcher
.saveToDisk(file
, false);
76 function content_handler_save_in (path
, inhibit_prompt
) {
77 path
= make_file(path
);
78 return function (ctx
) {
80 var suggested_path
= path
.clone();
81 suggested_path
.append(ctx
.launcher
.suggestedFileName
);
83 file
= suggested_path
;
85 file
= yield ctx
.window
.minibuffer
.read_file_check_overwrite(
86 $prompt
= "Save to file:",
87 $initial_value
= suggested_path
.path
,
90 register_download(ctx
.buffer
, ctx
.launcher
.source
);
91 ctx
.launcher
.saveToDisk(file
, false);
95 function content_handler_open (ctx
) {
96 var cwd
= with_current_buffer(ctx
.buffer
, function (I
) I
.local
.cwd
);
97 var mime_type
= ctx
.launcher
.MIMEInfo
.MIMEType
;
98 var suggested_action
= external_content_handlers
.get(mime_type
);
99 var command
= yield ctx
.window
.minibuffer
.read_shell_command(
100 $initial_value
= suggested_action
,
102 var file
= get_temporary_file(ctx
.launcher
.suggestedFileName
);
103 var info
= register_download(ctx
.buffer
, ctx
.launcher
.source
);
104 info
.temporary_status
= DOWNLOAD_TEMPORARY_FOR_COMMAND
;
105 info
.set_shell_command(command
, cwd
);
106 ctx
.launcher
.saveToDisk(file
, false);
109 function content_handler_open_default_viewer (ctx
) {
110 var cwd
= with_current_buffer(ctx
.buffer
, function (I
) I
.local
.cwd
);
111 var mime_type
= ctx
.launcher
.MIMEInfo
.MIMEType
;
112 var command
= external_content_handlers
.get(mime_type
);
114 command
= yield ctx
.window
.minibuffer
.read_shell_command(
115 $initial_value
= command
,
117 var file
= get_temporary_file(ctx
.launcher
.suggestedFileName
);
118 var info
= register_download(ctx
.buffer
, ctx
.launcher
.source
);
119 info
.temporary_status
= DOWNLOAD_TEMPORARY_FOR_COMMAND
;
120 info
.set_shell_command(command
, cwd
);
121 ctx
.launcher
.saveToDisk(file
, false);
124 function content_handler_open_url (ctx
) {
125 ctx
.abort(); // abort download
126 let mime_type
= ctx
.launcher
.MIMEInfo
.MIMEType
;
127 let cwd
= with_current_buffer(ctx
.buffer
, function (I
) I
.local
.cwd
);
128 let cmd
= yield ctx
.window
.minibuffer
.read_shell_command(
130 $initial_value
= external_content_handlers
.get(mime_type
));
131 shell_command_with_argument_blind(cmd
, ctx
.launcher
.source
.spec
, $cwd
= cwd
);
134 function content_handler_copy_url (ctx
) {
135 ctx
.abort(); // abort download
136 let uri
= ctx
.launcher
.source
.spec
;
137 writeToClipboard(uri
);
138 ctx
.window
.minibuffer
.message("Copied: " + uri
);
141 function content_handler_view_internally (ctx
) {
142 var suggested_type
= ctx
.launcher
.MIMEInfo
.MIMEType
;
143 if (viewable_mime_type_list
.indexOf(suggested_type
) == -1)
144 suggested_type
= "text/plain";
145 var mime_type
= yield ctx
.window
.minibuffer
.read_viewable_mime_type(
146 $prompt
= "View internally as",
147 $initial_value
= suggested_type
,
149 ctx
.abort(); // abort before reloading
150 override_mime_type_for_next_load(ctx
.launcher
.source
, mime_type
);
151 ctx
.frame
.location
= ctx
.launcher
.source
.spec
; // reload
154 function content_handler_view_as_text (ctx
) {
155 ctx
.abort(); // abort before reloading
156 override_mime_type_for_next_load(ctx
.launcher
.source
, "text/plain");
157 ctx
.frame
.location
= ctx
.launcher
.source
.spec
; // reload
160 function content_handler_prompt (ctx
) {
161 var action_chosen
= false;
162 var can_view_internally
= ctx
.frame
!= null &&
163 can_override_mime_type_for_uri(ctx
.launcher
.source
);
166 panel
= create_info_panel(ctx
.window
, "download-panel",
167 [["downloading", "Downloading:", ctx
.launcher
.source
.spec
],
168 ["mime-type", "Mime type:", ctx
.launcher
.MIMEInfo
.MIMEType
]]);
169 var action
= yield ctx
.window
.minibuffer
.read_single_character_option(
170 $prompt
= "Action to perform: (s: save; o: open; O: open URL; c: copy URL; " +
171 (can_view_internally
? "i: view internally; t: view as text)" : ")"),
172 $options
= (can_view_internally
? ["s", "o", "O", "c", "i", "t"] : ["s", "o", "O", "c"]));
175 yield content_handler_save(ctx
);
176 action_chosen
= true;
179 yield content_handler_open(ctx
);
180 action_chosen
= true;
183 yield content_handler_open_url(ctx
);
184 action_chosen
= true;
187 yield content_handler_copy_url(ctx
);
188 action_chosen
= true;
191 yield content_handler_view_internally(ctx
);
192 action_chosen
= true;
195 yield content_handler_view_as_text(ctx
);
196 action_chosen
= true;
200 handle_interactive_error(ctx
.window
, e
);
211 * download_helper implements nsIHelperAppLauncherDialog.
213 * Sometimes, like when following a link, the content type of the document
214 * cannot be displayed by Mozilla. When this happens, Mozilla calls the
215 * `show' method of our download_helper with a handle for the started
216 * download and other contextual information.
218 function download_helper () {}
219 download_helper
.prototype = {
220 constructor: download_helper
,
221 QueryInterface
: generate_QI(Ci
.nsIHelperAppLauncherDialog
,
222 Ci
.nsIWebProgressListener2
),
223 show: function (launcher
, context
, reason
) {
224 var ctx
= new content_handler_context(launcher
, context
);
226 ctx
.abort(); //XXX: impolite; need better solution.
230 // is there anything in content_handlers for this object?
231 var mime_type
= launcher
.MIMEInfo
.MIMEType
;
232 var action
= content_handlers
.get(mime_type
) ||
233 content_handler_prompt
;
234 co_call(action(ctx
));
236 handle_interactive_error(ctx
.window
, e
);
239 promptForSaveToFile: function (launcher
, context
, default_file
, suggested_file_extension
) {
244 provide("content-handler");