2 * (C) Copyright 2009 Shawn Betts
3 * (C) Copyright 2009,2011 John J. Foerch <jjfoerch@earthlink.net>
5 * Use, modification, and distribution are subject to the terms specified in the
12 define_variable("headings_xpath",
13 "//h1 | //h2 | //h3 | //h4 | //h5 | //h6 | //xhtml:h1 | "+
14 "//xhtml:h2 | //xhtml:h3 | //xhtml:h4 | //xhtml:h5 | //xhtml:h6",
15 "The xpath expression used by next-heading and previous-heading to find "+
16 "headings. Users will rarely need to change the value of this, but it "+
17 "exists especially for page-modes to override with a site-specific "+
21 define_variable("scroll_to_heading_wrap", true,
22 "If true, will wrap to the topmost heading when the viewport is at the "+
23 "bottom of the document and the user tries to access the next heading. "+
24 "Does the equivalent thing for \"previous heading\" as well.");
27 define_browser_object_class("next-heading", null,
29 let xpr = I.buffer.document.evaluate(
30 I.local.headings_xpath, I.buffer.document, xpath_lookup_namespace,
31 Ci.nsIDOMXPathResult.ORDERED_NODE_ITERATOR_TYPE, null),
32 heading, found = null, foundtop = null,
33 first = null, firsttop = null;
34 while ((heading = xpr.iterateNext())) {
35 let rect = heading.getBoundingClientRect();
36 if (rect.bottom - rect.top < 2)
38 if (! first || rect.top < firsttop) {
42 if (rect.top > 2 && (! found || rect.top < foundtop)) {
47 // scrollY can exceed scrollMaxY
48 let eod = I.buffer.scrollY - I.buffer.scrollMaxY >= 0;
49 if ((!found || eod) && scroll_to_heading_wrap)
51 yield co_return(found);
55 define_browser_object_class("previous-heading", null,
57 let xpr = I.buffer.document.evaluate(
58 I.local.headings_xpath, I.buffer.document, xpath_lookup_namespace,
59 Ci.nsIDOMXPathResult.ORDERED_NODE_ITERATOR_TYPE, null),
60 heading, found = null, foundtop = null,
61 last = null, lasttop = null;
62 while ((heading = xpr.iterateNext())) {
63 let rect = heading.getBoundingClientRect();
64 if (rect.bottom - rect.top < 2)
66 if (rect.top < -1 && (! found || rect.top > foundtop)) {
70 if (! last || rect.top > lasttop) {
75 if (! found && scroll_to_heading_wrap)
77 yield co_return(found);
82 var o = yield read_browser_object(I);
83 // no scrolling and no error if we failed to get an object.
86 if (o instanceof load_spec)
87 o = load_spec_element(o);
88 if (o instanceof Ci.nsIDOMWindow) {
89 // scroll to #ref or top
90 var ref = o.document.documentURIObject.ref;
92 var xpr = I.buffer.document.evaluate(
93 "//*[@id='"+ref+"']|//*[@name='"+ref+"']",
94 o.document, xpath_lookup_namespace,
95 Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE, null);
96 var node = xpr.singleNodeValue;
98 var rect = node.getBoundingClientRect();
99 o.scrollTo(0, o.scrollY + rect.top);
104 } else if (o instanceof Ci.nsIDOMNode) {
106 I.window.minibuffer.message(o.textContent);
108 throw interactive_error("Cannot scroll to given item");
113 interactive("scroll",
114 "Generalized scroll command.\nThe amount of scrolling is determined by "+
115 "the object passed to the command as a browser-object. If the object "+
116 "is a DOM node, that node will be scrolled to the top of the viewport "+
119 $browser_object = null);