Debian nightly builds: also upload .tar.xz files
[conkeror.git] / modules / scroll.js
blobdb0d66485023cde0d08b16b693f98d083906f37e
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 **/
9 define_variable("headings_xpath",
10     "//h1 | //h2 | //h3 | //h4 | //h5 | //h6 | //xhtml:h1 | "+
11     "//xhtml:h2 | //xhtml:h3 | //xhtml:h4 | //xhtml:h5 | //xhtml:h6",
12     "The xpath expression used by next-heading and previous-heading to find "+
13     "headings.  Users will rarely need to change the value of this, but it "+
14     "exists especially for page-modes to override with a site-specific "+
15     "xpath expression.");
18 define_variable("scroll_to_heading_wrap", true,
19     "If true, will wrap to the topmost heading when the viewport is at the "+
20     "bottom of the document and the user tries to access the next heading. "+
21     "Does the equivalent thing for \"previous heading\" as well.");
24 define_browser_object_class("next-heading", null,
25     function (I) {
26         let xpr = I.buffer.document.evaluate(
27             I.local.headings_xpath, I.buffer.document, xpath_lookup_namespace,
28             Ci.nsIDOMXPathResult.ORDERED_NODE_ITERATOR_TYPE, null),
29         heading, found = null, foundtop = null,
30         first = null, firsttop = null;
31         while ((heading = xpr.iterateNext())) {
32             let rect = heading.getBoundingClientRect();
33             if (rect.bottom - rect.top < 2)
34                 continue;
35             if (! first || rect.top < firsttop) {
36                 first = heading;
37                 firsttop = rect.top;
38             }
39             if (rect.top > 2 && (! found || rect.top < foundtop)) {
40                 found = heading;
41                 foundtop = rect.top;
42             }
43         }
44         // scrollY can exceed scrollMaxY
45         let eod = I.buffer.scrollY - I.buffer.scrollMaxY >= 0;
46         if ((!found || eod) && scroll_to_heading_wrap)
47             found = first;
48         yield co_return(found);
49     });
52 define_browser_object_class("previous-heading", null,
53     function (I) {
54         let xpr = I.buffer.document.evaluate(
55             I.local.headings_xpath, I.buffer.document,  xpath_lookup_namespace,
56             Ci.nsIDOMXPathResult.ORDERED_NODE_ITERATOR_TYPE, null),
57         heading, found = null, foundtop = null,
58         last = null, lasttop = null;
59         while ((heading = xpr.iterateNext())) {
60             let rect = heading.getBoundingClientRect();
61             if (rect.bottom - rect.top < 2)
62                 continue;
63             if (rect.top < -1 && (! found || rect.top > foundtop)) {
64                 found = heading;
65                 foundtop = rect.top;
66             }
67             if (! last || rect.top > lasttop) {
68                 last = heading;
69                 lasttop = rect.top;
70             }
71         }
72         if (! found && scroll_to_heading_wrap)
73             found = last;
74         yield co_return(found);
75     });
78 function scroll (I) {
79     var o = yield read_browser_object(I);
80     // no scrolling and no error if we failed to get an object.
81     if (! o)
82         yield co_return();
83     if (o instanceof load_spec)
84         o = load_spec_element(o);
85     if (o instanceof Ci.nsIDOMWindow) {
86         // scroll to #ref or top
87         var ref = o.document.documentURIObject.ref;
88         if (ref) {
89             var xpr = I.buffer.document.evaluate(
90                 "//*[@id='"+ref+"']|//*[@name='"+ref+"']",
91                 o.document, xpath_lookup_namespace,
92                 Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE, null);
93             var node = xpr.singleNodeValue;
94             if (node) {
95                 var rect = node.getBoundingClientRect();
96                 o.scrollTo(0, o.scrollY + rect.top);
97             } else
98                 o.scrollTo(0, 0);
99         } else
100             o.scrollTo(0, 0);
101     } else if (o instanceof Ci.nsIDOMNode) {
102         o.scrollIntoView();
103         I.window.minibuffer.message(o.textContent);
104     } else {
105         throw interactive_error("Cannot scroll to given item");
106     }
110 interactive("scroll",
111     "Generalized scroll command.\nThe amount of scrolling is determined by "+
112     "the object passed to the command as a browser-object.  If the object "+
113     "is a DOM node, that node will be scrolled to the top of the viewport "+
114     "if possible.",
115     scroll,
116     $browser_object = null);
118 provide("scroll");