.deb nightly builds: Make contact e-mail address configurable
[conkeror.git] / modules / scroll.js
bloba8a32ef73a3d6c8f5401d2e4e2f26bd7e03f8e16
1 /**
2  * (C) Copyright 2009 Shawn Betts
3  * (C) Copyright 2009 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 define_variable("headings_xpath",
11     "//h1 | //h2 | //h3 | //h4 | //h5 | //h6 | //xhtml:h1 | "+
12     "//xhtml:h2 | //xhtml:h3 | //xhtml:h4 | //xhtml:h5 | //xhtml:h6",
13     "The xpath expression used by next-heading and previous-heading to find "+
14     "headings.  Users will rarely need to change the value of this, but it "+
15     "exists especially for page-modes to override with a site-specific "+
16     "xpath expression.");
19 define_variable("scroll_to_heading_wrap", true,
20     "If true, will wrap to the topmost heading when the viewport is at the "+
21     "bottom of the document and the user tries to access the next heading. "+
22     "Does the equivalent thing for \"previous heading\" as well.");
25 define_browser_object_class("next-heading", null,
26     function (I) {
27         let xpr = I.buffer.document.evaluate(
28             I.local.headings_xpath, I.buffer.document, xpath_lookup_namespace,
29             Ci.nsIDOMXPathResult.ORDERED_NODE_ITERATOR_TYPE, null),
30         heading, found = null, foundtop = null,
31         first = null, firsttop = null;
32         while ((heading = xpr.iterateNext())) {
33             let rect = heading.getBoundingClientRect();
34             if (rect.bottom - rect.top < 2)
35                 continue;
36             if (! first || rect.top < firsttop) {
37                 first = heading;
38                 firsttop = rect.top;
39             }
40             if (rect.top > 2 && (! found || rect.top < foundtop)) {
41                 found = heading;
42                 foundtop = rect.top;
43             }
44         }
45         // scrollY can exceed scrollMaxY
46         let eod = I.buffer.scrollY - I.buffer.scrollMaxY >= 0;
47         if ((!found || eod) && scroll_to_heading_wrap)
48             found = first;
49         yield co_return(found);
50     });
53 define_browser_object_class("previous-heading", null,
54     function (I) {
55         let xpr = I.buffer.document.evaluate(
56             I.local.headings_xpath, I.buffer.document,  xpath_lookup_namespace,
57             Ci.nsIDOMXPathResult.ORDERED_NODE_ITERATOR_TYPE, null),
58         heading, found = null, foundtop = null,
59         last = null, lasttop = null;
60         while ((heading = xpr.iterateNext())) {
61             let rect = heading.getBoundingClientRect();
62             if (rect.bottom - rect.top < 2)
63                 continue;
64             if (rect.top < -1 && (! found || rect.top > foundtop)) {
65                 found = heading;
66                 foundtop = rect.top;
67             }
68             if (! last || rect.top > lasttop) {
69                 last = heading;
70                 lasttop = rect.top;
71             }
72         }
73         if (! found && scroll_to_heading_wrap)
74             found = last;
75         yield co_return(found);
76     });
79 function scroll (I) {
80     var element = yield read_browser_object(I);
81     // no scrolling and no error if we failed to get an object.
82     if (! element)
83         return;
84     element.scrollIntoView();
85     I.window.minibuffer.message(element.textContent);
89 interactive("scroll",
90     "Generalized scroll command.  The amount of scrolling is determined by "+
91     "the object passed to the command as a browser-object.  If the object "+
92     "is a DOM node, that node will be scrolled to the top of the viewport "+
93     "if possible.",
94     scroll);