Debian package: Support xulrunner 9+10 in debian/conkeror.bin, drop support for unver...
[conkeror.git] / modules / scroll.js
blob8db8bd5839c7b043b893b6bbaee2cfd1e68933f7
1 /**
2  * (C) Copyright 2009 Shawn Betts
3  * (C) Copyright 2009,2011 John J. Foerch <jjfoerch@earthlink.net>
4  *
5  * Use, modification, and distribution are subject to the terms specified in the
6  * COPYING file.
7 **/
10 in_module(null);
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 "+
18     "xpath expression.");
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,
28     function (I) {
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)
37                 continue;
38             if (! first || rect.top < firsttop) {
39                 first = heading;
40                 firsttop = rect.top;
41             }
42             if (rect.top > 2 && (! found || rect.top < foundtop)) {
43                 found = heading;
44                 foundtop = rect.top;
45             }
46         }
47         // scrollY can exceed scrollMaxY
48         let eod = I.buffer.scrollY - I.buffer.scrollMaxY >= 0;
49         if ((!found || eod) && scroll_to_heading_wrap)
50             found = first;
51         yield co_return(found);
52     });
55 define_browser_object_class("previous-heading", null,
56     function (I) {
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)
65                 continue;
66             if (rect.top < -1 && (! found || rect.top > foundtop)) {
67                 found = heading;
68                 foundtop = rect.top;
69             }
70             if (! last || rect.top > lasttop) {
71                 last = heading;
72                 lasttop = rect.top;
73             }
74         }
75         if (! found && scroll_to_heading_wrap)
76             found = last;
77         yield co_return(found);
78     });
81 function scroll (I) {
82     var o = yield read_browser_object(I);
83     // no scrolling and no error if we failed to get an object.
84     if (! o)
85         yield co_return();
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;
91         if (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;
97             if (node) {
98                 var rect = node.getBoundingClientRect();
99                 o.scrollTo(0, o.scrollY + rect.top);
100             } else
101                 o.scrollTo(0, 0);
102         } else
103             o.scrollTo(0, 0);
104     } else if (o instanceof Ci.nsIDOMNode) {
105         o.scrollIntoView();
106         I.window.minibuffer.message(o.textContent);
107     } else {
108         throw interactive_error("Cannot scroll to given item");
109     }
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 "+
117     "if possible.",
118     scroll,
119     $browser_object = null);
121 provide("scroll");