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