youtube: update scraper for youtube.com change
[conkeror.git] / modules / content-handler.js
blobaf1cf721e69ac820437f10e9edb0001c6c342919
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 () {}
30 /**
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.
34  */
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,
41         $select);
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) {
49         var file;
50         var suggested_path = path.clone();
51         suggested_path.append(ctx.launcher.suggestedFileName);
52         if (inhibit_prompt)
53             file = suggested_path;
54         else {
55             file = yield ctx.window.minibuffer.read_file_check_overwrite(
56                 $prompt = "Save to file:",
57                 $initial_value = suggested_path.path,
58                 $select);
59         }
60         register_download(ctx.buffer, ctx.launcher.source);
61         ctx.launcher.saveToDisk(file, false);
62     };
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,
71         $cwd = cwd);
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);
83     if (command == null)
84         command = yield ctx.window.minibuffer.read_shell_command(
85             $initial_value = command,
86             $cwd = cwd);
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(
99         $cwd = cwd,
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,
118         $select);
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);
134     var panel;
135     try {
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"]));
143         switch (action) {
144         case "s":
145             yield content_handler_save(ctx);
146             action_chosen = true;
147             break;
148         case "o":
149             yield content_handler_open(ctx);
150             action_chosen = true;
151             break;
152         case "O":
153             yield content_handler_open_url(ctx);
154             action_chosen = true;
155             break;
156         case "c":
157             yield content_handler_copy_url(ctx);
158             action_chosen = true;
159             break;
160         case "i":
161             yield content_handler_view_internally(ctx);
162             action_chosen = true;
163             break;
164         case "t":
165             yield content_handler_view_as_text(ctx);
166             action_chosen = true;
167             break;
168         }
169     } catch (e) {
170         handle_interactive_error(ctx.window, e);
171     } finally {
172         if (! action_chosen)
173             ctx.abort();
174         if (panel)
175             panel.destroy();
176     }
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.
187  */
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);
202         };
203         // then set frame, window, and buffer in the context, so that
204         // action handlers can use them if needed.
205         try {
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);
210         } catch (e) {
211             ctx.window = get_recent_conkeror_window();
212             if (! ctx.window) {
213                 // FIXME: need to handle this case perhaps where no windows exist
214                 ctx.abort(); // for now, just cancel the download
215                 return;
216             }
217             ctx.buffer = ctx.window.buffers.current;
218             ctx.frame = ctx.buffer.focused_frame;
219         }
220         try {
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));
226         } catch (e) {
227             handle_interactive_error(ctx.window, e);
228         }
229     },
231     promptForSaveToFile: function (launcher, context, default_file, suggested_file_extension) {
232         return null;
233     }
236 provide("content-handler");