1 require_later("content-buffer-input.js");
3 define_buffer_local_hook("content_buffer_finished_loading_hook");
4 define_buffer_local_hook("content_buffer_progress_change_hook");
5 define_buffer_local_hook("content_buffer_location_change_hook");
6 define_buffer_local_hook("content_buffer_status_change_hook");
7 define_buffer_local_hook("content_buffer_focus_change_hook");
8 define_buffer_local_hook("content_buffer_overlink_change_hook");
10 define_current_buffer_hook("current_content_buffer_finished_loading_hook", "content_buffer_finished_loading_hook");
11 define_current_buffer_hook("current_content_buffer_progress_change_hook", "content_buffer_progress_change_hook");
12 define_current_buffer_hook("current_content_buffer_location_change_hook", "content_buffer_location_change_hook");
13 define_current_buffer_hook("current_content_buffer_status_change_hook", "content_buffer_status_change_hook");
14 define_current_buffer_hook("current_content_buffer_focus_change_hook", "content_buffer_focus_change_hook");
15 define_current_buffer_hook("current_content_buffer_overlink_change_hook", "content_buffer_overlink_change_hook");
17 /* If browser is null, create a new browser */
18 define_keywords("$load");
19 function content_buffer(window, element)
22 conkeror.buffer.call(this, window, element, forward_keywords(arguments));
24 this.browser.addProgressListener(this);
26 this.browser.addEventListener("DOMTitleChanged", function (event) {
27 buffer_title_change_hook.run(buffer);
28 }, true /* capture */, false /* ignore untrusted events */);
30 this.browser.addEventListener("scroll", function (event) {
31 buffer_scroll_hook.run(buffer);
32 }, true /* capture */, false /* ignore untrusted events */);
34 this.browser.addEventListener("focus", function (event) {
35 content_buffer_focus_change_hook.run(buffer, event);
36 }, true /* capture */, false /* ignore untrusted events */);
38 this.browser.addEventListener("mouseover", function (event) {
39 if (event.target instanceof Ci.nsIDOMHTMLAnchorElement) {
40 content_buffer_overlink_change_hook.run(buffer, event.target.href);
41 buffer.current_overlink = event.target;
45 this.browser.addEventListener("mouseout", function (event) {
46 if (buffer.current_overlink == event.target) {
47 buffer.current_overlink = null;
48 content_buffer_overlink_change_hook.run(buffer, "");
52 this.browser.addEventListener("mousedown", function (event) {
53 buffer.last_user_input_received = Date.now();
56 this.browser.addEventListener("keypress", function (event) {
57 buffer.last_user_input_received = Date.now();
60 buffer.last_user_input_received = null;
62 /* FIXME: Add a handler for blocked popups, and also PopupWindow event */
64 this.browser.addEventListener("DOMPopupBlocked", function (event) {
65 dumpln("PopupWindow: " + event);
69 content_buffer_normal_input_mode(this);
71 var load_spec = arguments.$load;
75 content_buffer.prototype = {
76 constructor : content_buffer,
78 get scrollX () { return this.top_frame.scrollX; },
79 get scrollY () { return this.top_frame.scrollY; },
80 get scrollMaxX () { return this.top_frame.scrollMaxX; },
81 get scrollMaxY () { return this.top_frame.scrollMaxY; },
84 /* Used to display the correct URI when the buffer opens initially
85 * even before loading has progressed far enough for currentURI to
86 * contain the correct URI. */
89 get display_URI_string () {
90 if (this._display_URI)
91 return this._display_URI;
92 return this.current_URI.spec;
95 get title() { return this.browser.contentTitle; },
96 get description () { return this.display_URI_string; },
98 load : function (load_spec) {
99 apply_load_spec(this, load_spec);
102 _requests_started: 0,
103 _requests_finished: 0,
105 /* nsIWebProgressListener */
106 QueryInterface: generate_QI(Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference),
108 // This method is called to indicate state changes.
109 onStateChange: function(webProgress, request, stateFlags, status) {
110 const WPL = Components.interfaces.nsIWebProgressListener;
113 if (stateFlags & WPL.STATE_START)
115 if (stateFlags & WPL.STATE_STOP)
117 if (stateFlags & WPL.STATE_IS_REQUEST)
118 flagstr += ",request";
119 if (stateFlags & WPL.STATE_IS_DOCUMENT)
120 flagstr += ",document";
121 if (stateFlags & WPL.STATE_IS_NETWORK)
122 flagstr += ",network";
123 if (stateFlags & WPL.STATE_IS_WINDOW)
124 flagstr += ",window";
125 dumpln("onStateChange: " + flagstr + ", status: " + status);
127 if (stateFlags & WPL.STATE_IS_REQUEST) {
128 if (stateFlags & WPL.STATE_START) {
129 if (this._requests_started == 0) {
130 // Reset the time at which the last user input was received for the page
131 this.last_user_input_received = 0;
133 this._requests_started++;
134 } else if (stateFlags & WPL.STATE_STOP) {
135 this._requests_finished++;
138 if ((stateFlags & WPL.STATE_STOP) && (this._requests_finished == this._requests_started)) {
139 this._requests_finished = this._requests_started = 0;
140 content_buffer_finished_loading_hook.run(this);
144 /* This method is called to indicate progress changes for the currently
146 onProgressChange: function(webProgress, request, curSelf, maxSelf,
147 curTotal, maxTotal) {
148 content_buffer_progress_change_hook.run(this, request, curSelf, maxSelf, curTotal, maxTotal);
151 /* This method is called to indicate a change to the current location.
152 The url can be gotten as location.spec. */
153 onLocationChange : function(webProgress, request, location) {
154 /* Use the real location URI now */
155 this._display_URI = null;
156 content_buffer_location_change_hook.run(this, request, location);
159 // This method is called to indicate a status changes for the currently
160 // loading page. The message is already formatted for display.
161 // Status messages could be displayed in the minibuffer output area.
162 onStatusChange: function(webProgress, request, status, msg) {
163 content_buffer_status_change_hook.run(this, request, status, msg);
166 // This method is called when the security state of the browser changes.
167 onSecurityChange: function(webProgress, request, state) {
168 const WPL = Components.interfaces.nsIWebProgressListener;
170 if (state & WPL.STATE_IS_INSECURE) {
171 // update visual indicator
173 var level = "unknown";
174 if (state & WPL.STATE_IS_SECURE) {
175 if (state & WPL.STATE_SECURE_HIGH)
177 else if (state & WPL.STATE_SECURE_MED)
179 else if (state & WPL.STATE_SECURE_LOW)
181 } else if (state & WPL_STATE_IS_BROKEN) {
184 // provide a visual indicator of the security state here.
188 /* Inherit from buffer */
190 __proto__ : buffer.prototype
194 add_hook("current_content_buffer_finished_loading_hook",
196 buffer.window.minibuffer.show("Done");
199 add_hook("current_content_buffer_status_change_hook",
200 function (buffer, request, status, msg) {
201 buffer.window.minibuffer.show(msg);
206 //RETROJ: this may be improperly named. it can read either an url or a
207 // webjump from the minibuffer, but it will always return an url.
208 I.url_or_webjump = interactive_method(
209 $async = function (ctx, cont) {
210 keywords(arguments, $prompt = "URL:", $history = "url", $initial_value = "");
211 var completions = arguments.$completions;
212 if (completions === undefined)
215 for (var x in gWebJumpLocations)
216 completions.push([x,x]);
218 ctx.window.minibuffer.read_with_completion(
219 $prompt = arguments.$prompt,
220 $history = arguments.$history,
221 $completions = completions,
222 $initial_value = arguments.$initial_value,
225 $callback = function (match,s) {
226 if (s == "") // well-formedness check. (could be better!)
227 throw ("invalid url or webjump (\""+s+"\")");
228 cont(get_url_or_webjump (s));
232 I.current_frame_url = interactive_method(
233 $sync = function (ctx) {
234 var buffer = ctx.buffer;
235 if (!(buffer instanceof content_buffer))
236 throw new Error("Current buffer is of invalid type");
237 return buffer.focused_frame.location.href;
240 // This name should probably change
241 I.current_url = interactive_method(
242 $sync = function (ctx) {
243 var buffer = ctx.buffer;
244 if (!(buffer instanceof content_buffer))
245 throw new Error("Current buffer is of invalid type");
246 return buffer.current_URI.spec;
249 I.focused_link_url = interactive_method(
250 $sync = function (ctx) {
251 var buffer = ctx.buffer;
252 if (!(buffer instanceof content_buffer))
253 throw new Error("Current buffer is of invalid type");
254 // -- Focused link element
255 ///JJF: check for errors or wrong element type.
256 return get_link_location (buffer.focused_element);
259 I.content_charset = interactive_method(
260 $sync = function (ctx) {
261 var buffer = ctx.buffer;
262 if (!(buffer instanceof content_buffer))
263 throw new Error("Current buffer is of invalid type");
264 // -- Charset of content area of focusedWindow
265 var focusedWindow = buffer.focused_frame;
267 return focusedWindow.document.characterSet;
273 I.content_selection = interactive_method(
274 $sync = function (ctx) {
275 // -- Selection of content area of focusedWindow
276 var focusedWindow = this.buffers.current.focused_frame;
277 return focusedWindow.getSelection ();
280 function overlink_update_status(buffer, text) {
282 buffer.window.minibuffer.show("Link: " + text);
284 buffer.window.minibuffer.show("");
287 define_global_mode("overlink_mode",
289 add_hook("current_content_buffer_overlink_change_hook", overlink_update_status);
292 remove_hook("current_content_buffer_overlink_change_hook", overlink_update_status);
298 function document_load_spec(doc) {
299 var sh_entry = get_SHEntry_for_document(doc);
300 var result = {url: doc.location.href};
301 result.document = doc;
302 if (sh_entry != null) {
303 result.cache_key = sh_entry;
304 result.referrer = sh_entry.referrerURI;
305 result.post_data = sh_entry.postData;
310 /* Target can be either a content_buffer or an nsIWebNavigation */
311 function apply_load_spec(target, load_spec) {
312 var url, flags, referrer, post_data;
313 if (typeof(load_spec) == "string") {
320 flags = load_spec.flags;
321 referrer = load_spec.referrer;
322 post_data = load_spec.post_data;
325 flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
326 if (target instanceof content_buffer) {
327 target._display_URI = url;
328 target = target.web_navigation;
330 target.loadURI(url, flags, referrer, post_data, null /* headers */);
333 function open_in_browser(buffer, target, load_spec)
336 case OPEN_CURRENT_BUFFER:
338 case FOLLOW_CURRENT_FRAME:
339 case FOLLOW_TOP_FRAME:
340 if (buffer instanceof content_buffer) {
341 apply_load_spec(buffer, load_spec);
344 target = OPEN_NEW_BUFFER;
345 // If the current buffer is not a content_buffer, use a new buffer.
347 create_buffer(buffer.window,
348 buffer_creator(content_buffer,
350 $configuration = buffer.configuration),
356 interactive("open-url",
357 "Open a URL, reusing the current buffer by default",
359 I.current_buffer, $$ = I.browse_target("open"),
360 I.url_or_webjump($prompt = I.bind(browse_target_prompt, $$)));
362 interactive("find-alternate-url",
363 "Edit the current URL in the minibuffer",
365 I.current_buffer, $$ = I.browse_target("open"),
366 I.url_or_webjump($prompt = I.bind(browse_target_prompt, $$),
367 $initial_value = I.current_url));
369 interactive("find-url",
370 "Open a URL in a new buffer",
372 I.current_buffer, $$ = I.browse_target("find-url"),
373 I.url_or_webjump($prompt = I.bind(browse_target_prompt, $$)));
374 default_browse_targets["find-url"] = [OPEN_NEW_BUFFER, OPEN_NEW_WINDOW];
377 function go_up (b, target)
379 open_in_browser(b, target, b.current_URI.resolve (".."));
382 "Go to the parent directory of the current URL",
384 I.current_buffer(content_buffer),
385 I.browse_target("go-up"));
386 default_browse_targets["go-up"] = "open";
389 function go_back (b, prefix)
392 go_forward(b, -prefix);
394 if (b.web_navigation.canGoBack)
396 var hist = b.web_navigation.sessionHistory;
397 var idx = hist.index - prefix;
400 b.web_navigation.gotoIndex(idx);
402 throw interactive_error("Can't go back");
404 interactive("go-back",
405 "Go back in the session hisory for the current buffer.",
406 go_back, I.current_buffer(content_buffer), I.p);
409 function go_forward (b, prefix)
414 if (b.web_navigation.canGoForward)
416 var hist = b.web_navigation.sessionHistory;
417 var idx = hist.index + prefix;
418 if (idx >= hist.count) idx = hist.count-1;
419 b.web_navigation.gotoIndex(idx);
421 throw interactive_error("Can't go forward");
423 interactive("go-forward",
424 "Go back in the session hisory for the current buffer.",
425 go_forward, I.current_buffer(content_buffer), I.p);
427 function stop_loading (b)
429 b.web_navigation.stop(Ci.nsIWebNavigation.STOP_NETWORK);
431 interactive("stop-loading",
432 "Stop loading the current document.",
433 stop_loading, I.current_buffer(content_buffer));
435 function reload (b, bypass_cache)
437 var flags = bypass_cache != null ?
438 Ci.nsIWebNavigation.LOAD_FLAGS_NONE : Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
439 b.web_navigation.reload(flags);
441 interactive("reload",
442 "Reload the current document.\n" +
443 "If a prefix argument is specified, the cache is bypassed.",
444 reload, I.current_buffer(content_buffer), I.P);
447 * browserDOMWindow: intercept window opening
449 function initialize_browser_dom_window(window) {
450 window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow =
451 new browser_dom_window(window);
454 /* USER PREFERENCE */
455 /* This will generally be OPEN_NEW_BUFFER, OPEN_NEW_BUFFER_BACKGROUND, or OPEN_NEW_WINDOW */
456 var browser_default_open_target = OPEN_NEW_BUFFER;
458 function browser_dom_window(window) {
459 this.window = window;
460 this.next_target = null;
462 browser_dom_window.prototype = {
463 QueryInterface: generate_QI(Ci.nsIBrowserDOMWindow),
465 openURI : function(aURI, aOpener, aWhere, aContext) {
467 // Reference: http://www.xulplanet.com/references/xpcomref/ifaces/nsIBrowserDOMWindow.html
468 var target = this.next_target;
469 if (target == null || target == FOLLOW_DEFAULT)
470 target = browser_default_open_target;
471 this.next_target = null;
473 /* Determine the opener buffer */
474 var opener_buffer = get_buffer_from_frame(this.window, aOpener.top);
475 var config = opener_buffer ? opener_buffer.configuration : null;
477 switch (browser_default_open_target) {
478 case OPEN_CURRENT_BUFFER:
479 case FOLLOW_TOP_FRAME:
481 case FOLLOW_CURRENT_FRAME:
483 case OPEN_NEW_BUFFER:
484 var buffer = new content_buffer(this.window, null /* element */, $configuration = config);
485 this.window.buffers.current = buffer;
486 return buffer.top_frame;
487 case OPEN_NEW_BUFFER_BACKGROUND:
488 var buffer = new content_buffer(this.window, null /* element */, $configuration = config);
489 return buffer.top_frame;
490 case OPEN_NEW_WINDOW:
491 default: /* shouldn't be needed */
493 /* We don't call make_window here, because that will result
494 * in the URL being loaded as the top-level document,
495 * instead of within a browser buffer. Instead, we can
496 * rely on Mozilla using browser.chromeURL. */
497 window_set_extra_arguments({initial_buffer_configuration: config});
503 add_hook("window_initialize_early_hook", initialize_browser_dom_window);