follow-relationship: allow relationship patterns to be functions
[conkeror.git] / modules / follow-relationship.js
blob6d3f016595ab6212204ac2e815a64b97968b50b6
1 /**
2  * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
3  *
4  * Portions of this file were derived from Vimperator,
5  * (C) Copyright 2007 Doug Kearns
6  * (C) Copyright 2007-2008 Martin Stubenschrott.
7  *
8  * Use, modification, and distribution are subject to the terms specified in the
9  * COPYING file.
10 **/
12 require("element.js");
14 const RELATIONSHIP_NEXT = 0;
15 const RELATIONSHIP_PREVIOUS = 1;
17 var browser_relationship_rel_regexp = ["next", "prev|previous"];
18 var browser_relationship_rev_regexp = ["prev|previous", "next"];
20 define_variable("browser_relationship_patterns", {},
21     "Patterns used by `follow-next' and `follow-previous'. "+
22     "User value may be overridden for specific websites by "+
23     "page-modes.");
25 browser_relationship_patterns[RELATIONSHIP_NEXT] =
26     [/^next$/i,
27      new RegExp("^>$","i"),
28      new RegExp("^(>>|»)$","i"),
29      new RegExp("^(>|»)","i"),
30      new RegExp("(>|»)$","i"),
31      new RegExp("\\bnext","i")
32     ];
34 browser_relationship_patterns[RELATIONSHIP_PREVIOUS] =
35     [/^(prev|previous)$/i,
36      new RegExp("^<$","i"),
37      new RegExp("^(<<|«)$","i"),
38      new RegExp("^(<|«)","i"),
39      new RegExp("(<|«)$","i"),
40      new RegExp("\\bprev|previous\\b","i")
41     ];
43 function document_get_element_by_relationship (doc, patterns, relationship) {
44     patterns = patterns[relationship];
45     var rel_name = new RegExp(browser_relationship_rel_regexp[relationship], "i");
46     var rev_name = new RegExp(browser_relationship_rev_regexp[relationship], "i");
48     var elems = doc.getElementsByTagName("link");
49     // links have higher priority than anchors
50     for (var i = 0, n = elems.length; i < n; i++) {
51         if (rel_name.test(elems[i].rel) || rev_name.test(elems[i].rev))
52             return elems[i];
53     }
55     // no links? look for anchors
56     elems = doc.getElementsByTagName("a");
57     for (i = 0, n = elems.length; i < n; i++) {
58         if (rel_name.test(elems[i].rel) || rev_name.test(elems[i].rev))
59             return elems[i];
60     }
62     for (var j = 0, p = patterns.length; j < p; ++j) {
63         var pattern = patterns[j];
64         if (pattern instanceof Function) {
65             var elem = pattern(doc);
66             if (elem)
67                 return elem;
68         } else {
69             for (i = 0, n = elems.length; i < n; i++) { // loop through list of anchors again
70                 if (pattern.test(elems[i].textContent))
71                     return elems[i];
72                 // images with alt text being href
73                 var children = elems[i].childNodes;
74                 for (var k = 0, c = children.length; k < c; k++) {
75                     if (children[k].alt && pattern.test(children[k].alt))
76                         return elems[i];
77                 }
78             }
79         }
80     }
81     return null;
84 define_browser_object_class("relationship-next", null,
85     function (I, prompt) {
86         var doc = I.buffer.document;
87         for (let frame in frame_iterator(I.buffer.top_frame, I.buffer.focused_frame)) {
88             let elem = document_get_element_by_relationship(
89                 frame.document,
90                 I.local.browser_relationship_patterns,
91                 RELATIONSHIP_NEXT);
92             if (elem)
93                 yield co_return(elem);
94         }
95         throw interactive_error("No \"next\" link found.");
96     });
98 define_browser_object_class("relationship-previous", null,
99     function (I, prompt) {
100         var doc = I.buffer.document;
101         for (let frame in frame_iterator(I.buffer.top_frame, I.buffer.focused_frame)) {
102             let elem = document_get_element_by_relationship(
103                 frame.document,
104                 I.local.browser_relationship_patterns,
105                 RELATIONSHIP_PREVIOUS);
106             if (elem)
107                 yield co_return(elem);
108         }
109         throw interactive_error("No \"previous\" link found.");
110     });
112 provide("follow-relationship");