rdoc 6.17.0 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +196 -0
- data/LEGAL.rdoc +6 -0
- data/README.md +90 -7
- data/doc/markup_reference/markdown.md +558 -0
- data/doc/markup_reference/rdoc.rdoc +1169 -0
- data/lib/rdoc/code_object/any_method.rb +15 -7
- data/lib/rdoc/code_object/attr.rb +2 -1
- data/lib/rdoc/code_object/class_module.rb +62 -11
- data/lib/rdoc/code_object/constant.rb +9 -0
- data/lib/rdoc/code_object/context/section.rb +46 -9
- data/lib/rdoc/code_object/context.rb +15 -4
- data/lib/rdoc/code_object/method_attr.rb +13 -1
- data/lib/rdoc/code_object/mixin.rb +3 -0
- data/lib/rdoc/code_object/top_level.rb +15 -1
- data/lib/rdoc/comment.rb +1 -1
- data/lib/rdoc/cross_reference.rb +31 -24
- data/lib/rdoc/generator/aliki.rb +141 -0
- data/lib/rdoc/generator/darkfish.rb +3 -1
- data/lib/rdoc/generator/template/aliki/_footer.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_head.rhtml +9 -4
- data/lib/rdoc/generator/template/aliki/_header.rhtml +4 -4
- data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_sidebar_search.rhtml +3 -3
- data/lib/rdoc/generator/template/aliki/class.rhtml +17 -17
- data/lib/rdoc/generator/template/aliki/css/rdoc.css +278 -60
- data/lib/rdoc/generator/template/aliki/index.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/js/aliki.js +51 -23
- data/lib/rdoc/generator/template/aliki/js/bash_highlighter.js +167 -0
- data/lib/rdoc/generator/template/aliki/js/c_highlighter.js +1 -1
- data/lib/rdoc/generator/template/aliki/js/{search.js → search_controller.js} +16 -7
- data/lib/rdoc/generator/template/aliki/js/search_navigation.js +105 -0
- data/lib/rdoc/generator/template/aliki/js/search_ranker.js +239 -0
- data/lib/rdoc/generator/template/aliki/page.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +1 -1
- data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +1 -1
- data/lib/rdoc/generator/template/darkfish/class.rhtml +11 -11
- data/lib/rdoc/generator/template/darkfish/css/rdoc.css +19 -0
- data/lib/rdoc/markdown.kpeg +22 -12
- data/lib/rdoc/markdown.rb +36 -26
- data/lib/rdoc/markup/blank_line.rb +25 -23
- data/lib/rdoc/markup/element.rb +21 -0
- data/lib/rdoc/markup/formatter.rb +129 -106
- data/lib/rdoc/markup/hard_break.rb +30 -27
- data/lib/rdoc/markup/heading.rb +166 -77
- data/lib/rdoc/markup/inline_parser.rb +312 -0
- data/lib/rdoc/markup/parser.rb +1 -1
- data/lib/rdoc/markup/raw.rb +52 -55
- data/lib/rdoc/markup/table.rb +48 -40
- data/lib/rdoc/markup/to_ansi.rb +51 -4
- data/lib/rdoc/markup/to_bs.rb +22 -42
- data/lib/rdoc/markup/to_html.rb +178 -183
- data/lib/rdoc/markup/to_html_crossref.rb +58 -79
- data/lib/rdoc/markup/to_html_snippet.rb +62 -62
- data/lib/rdoc/markup/to_label.rb +29 -20
- data/lib/rdoc/markup/to_markdown.rb +61 -37
- data/lib/rdoc/markup/to_rdoc.rb +86 -26
- data/lib/rdoc/markup/to_test.rb +9 -1
- data/lib/rdoc/markup/to_tt_only.rb +10 -16
- data/lib/rdoc/markup/verbatim.rb +1 -1
- data/lib/rdoc/markup.rb +11 -32
- data/lib/rdoc/options.rb +1 -1
- data/lib/rdoc/parser/changelog.rb +29 -0
- data/lib/rdoc/parser/prism_ruby.rb +44 -32
- data/lib/rdoc/parser/ruby.rb +1 -1
- data/lib/rdoc/rubygems_hook.rb +3 -3
- data/lib/rdoc/text.rb +44 -5
- data/lib/rdoc/token_stream.rb +4 -8
- data/lib/rdoc/version.rb +1 -1
- data/rdoc.gemspec +3 -3
- metadata +13 -15
- data/CONTRIBUTING.rdoc +0 -219
- data/ExampleMarkdown.md +0 -39
- data/ExampleRDoc.rdoc +0 -210
- data/lib/rdoc/markup/attr_changer.rb +0 -22
- data/lib/rdoc/markup/attr_span.rb +0 -35
- data/lib/rdoc/markup/attribute_manager.rb +0 -405
- data/lib/rdoc/markup/attributes.rb +0 -70
- data/lib/rdoc/markup/regexp_handling.rb +0 -40
|
@@ -28,7 +28,7 @@ function createSearchInstance(input, result) {
|
|
|
28
28
|
|
|
29
29
|
result.classList.remove("initially-hidden");
|
|
30
30
|
|
|
31
|
-
const search = new
|
|
31
|
+
const search = new SearchController(search_data, input, result);
|
|
32
32
|
|
|
33
33
|
search.renderItem = function(result) {
|
|
34
34
|
const li = document.createElement('li');
|
|
@@ -40,8 +40,12 @@ function createSearchInstance(input, result) {
|
|
|
40
40
|
html += `<span class="params">${result.params}</span>`;
|
|
41
41
|
html += '</a>';
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
// Add type indicator
|
|
44
|
+
if (result.type) {
|
|
45
|
+
const typeLabel = this.formatType(result.type);
|
|
46
|
+
const typeClass = result.type.replace(/_/g, '-');
|
|
47
|
+
html += `<span class="search-type search-type-${this.escapeHTML(typeClass)}">${typeLabel}</span>`;
|
|
48
|
+
}
|
|
45
49
|
|
|
46
50
|
if (result.snippet)
|
|
47
51
|
html += `<div class="search-snippet">${result.snippet}</div>`;
|
|
@@ -51,26 +55,27 @@ function createSearchInstance(input, result) {
|
|
|
51
55
|
return li;
|
|
52
56
|
}
|
|
53
57
|
|
|
54
|
-
search.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
window.location.href = href;
|
|
58
|
+
search.formatType = function(type) {
|
|
59
|
+
const typeLabels = {
|
|
60
|
+
'class': 'class',
|
|
61
|
+
'module': 'module',
|
|
62
|
+
'constant': 'const',
|
|
63
|
+
'instance_method': 'method',
|
|
64
|
+
'class_method': 'method'
|
|
65
|
+
};
|
|
66
|
+
return typeLabels[type] || type;
|
|
64
67
|
}
|
|
65
68
|
|
|
66
|
-
search.
|
|
69
|
+
search.select = function(result) {
|
|
70
|
+
window.location.href = result.firstChild.firstChild.href;
|
|
71
|
+
}
|
|
67
72
|
|
|
68
73
|
return search;
|
|
69
74
|
}
|
|
70
75
|
|
|
71
76
|
function hookSearch() {
|
|
72
77
|
const input = document.querySelector('#search-field');
|
|
73
|
-
const result = document.querySelector('#search-results');
|
|
78
|
+
const result = document.querySelector('#search-results-desktop');
|
|
74
79
|
|
|
75
80
|
if (!input || !result) return; // Exit if search elements not found
|
|
76
81
|
|
|
@@ -82,15 +87,35 @@ function hookSearch() {
|
|
|
82
87
|
const search = createSearchInstance(input, result);
|
|
83
88
|
if (!search) return;
|
|
84
89
|
|
|
90
|
+
// Hide search results when clicking outside the search area
|
|
91
|
+
document.addEventListener('click', (e) => {
|
|
92
|
+
if (!e.target.closest('.navbar-search-desktop')) {
|
|
93
|
+
search.hide();
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Hide search results on Escape key on desktop too
|
|
98
|
+
document.addEventListener('keydown', (e) => {
|
|
99
|
+
if (e.key === 'Escape' && input.matches(":focus")) {
|
|
100
|
+
search.hide();
|
|
101
|
+
input.blur();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Show search results when focusing on input (if there's a query)
|
|
106
|
+
input.addEventListener('focus', () => {
|
|
107
|
+
if (input.value.trim()) {
|
|
108
|
+
search.show();
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
85
112
|
// Check for ?q= URL parameter and trigger search automatically
|
|
86
113
|
if (typeof URLSearchParams !== 'undefined') {
|
|
87
114
|
const urlParams = new URLSearchParams(window.location.search);
|
|
88
115
|
const queryParam = urlParams.get('q');
|
|
89
116
|
if (queryParam) {
|
|
90
|
-
const navParam = urlParams.get('nav');
|
|
91
|
-
const autoSelect = navParam !== '0';
|
|
92
117
|
input.value = queryParam;
|
|
93
|
-
search.search(queryParam,
|
|
118
|
+
search.search(queryParam, false);
|
|
94
119
|
}
|
|
95
120
|
}
|
|
96
121
|
}
|
|
@@ -143,9 +168,12 @@ function hookSidebar() {
|
|
|
143
168
|
});
|
|
144
169
|
|
|
145
170
|
const isSmallViewport = window.matchMedia("(max-width: 1023px)").matches;
|
|
146
|
-
if (isSmallViewport) {
|
|
147
|
-
closeNav();
|
|
148
171
|
|
|
172
|
+
// The sidebar is hidden by default with the `hidden` attribute
|
|
173
|
+
// On large viewports, we display the sidebar with JavaScript
|
|
174
|
+
// This is better than the opposite approach of hiding it with JavaScript
|
|
175
|
+
// because it avoids flickering the sidebar when the page is loaded, especially on mobile devices
|
|
176
|
+
if (isSmallViewport) {
|
|
149
177
|
// Close nav when clicking links inside it
|
|
150
178
|
document.addEventListener('click', (e) => {
|
|
151
179
|
if (e.target.closest('#navigation a')) {
|
|
@@ -161,6 +189,8 @@ function hookSidebar() {
|
|
|
161
189
|
closeNav();
|
|
162
190
|
}
|
|
163
191
|
});
|
|
192
|
+
} else {
|
|
193
|
+
openNav();
|
|
164
194
|
}
|
|
165
195
|
}
|
|
166
196
|
|
|
@@ -363,9 +393,7 @@ function hookSearchModal() {
|
|
|
363
393
|
if (queryParam && isSmallViewport) {
|
|
364
394
|
openSearchModal();
|
|
365
395
|
searchInput.value = queryParam;
|
|
366
|
-
|
|
367
|
-
const autoSelect = navParam !== '0';
|
|
368
|
-
mobileSearch.search(queryParam, autoSelect);
|
|
396
|
+
mobileSearch.search(queryParam, false);
|
|
369
397
|
}
|
|
370
398
|
}
|
|
371
399
|
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side shell syntax highlighter for RDoc
|
|
3
|
+
* Highlights: $ prompts, commands, options, strings, env vars, comments
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
(function() {
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
function escapeHtml(text) {
|
|
10
|
+
return text
|
|
11
|
+
.replace(/&/g, '&')
|
|
12
|
+
.replace(/</g, '<')
|
|
13
|
+
.replace(/>/g, '>')
|
|
14
|
+
.replace(/"/g, '"')
|
|
15
|
+
.replace(/'/g, ''');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function wrap(className, text) {
|
|
19
|
+
return '<span class="' + className + '">' + escapeHtml(text) + '</span>';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function highlightLine(line) {
|
|
23
|
+
if (line.trim() === '') return escapeHtml(line);
|
|
24
|
+
|
|
25
|
+
var result = '';
|
|
26
|
+
var i = 0;
|
|
27
|
+
var len = line.length;
|
|
28
|
+
|
|
29
|
+
// Preserve leading whitespace
|
|
30
|
+
while (i < len && (line[i] === ' ' || line[i] === '\t')) {
|
|
31
|
+
result += escapeHtml(line[i++]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Check for $ prompt ($ followed by space or end of line)
|
|
35
|
+
if (line[i] === '$' && (line[i + 1] === ' ' || line[i + 1] === undefined)) {
|
|
36
|
+
result += wrap('sh-prompt', '$');
|
|
37
|
+
i++;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Check for # comment at start
|
|
41
|
+
if (line[i] === '#') {
|
|
42
|
+
return result + wrap('sh-comment', line.slice(i));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var seenCommand = false;
|
|
46
|
+
var afterSpace = true;
|
|
47
|
+
|
|
48
|
+
while (i < len) {
|
|
49
|
+
var ch = line[i];
|
|
50
|
+
|
|
51
|
+
// Whitespace
|
|
52
|
+
if (ch === ' ' || ch === '\t') {
|
|
53
|
+
result += escapeHtml(ch);
|
|
54
|
+
i++;
|
|
55
|
+
afterSpace = true;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Comment after whitespace
|
|
60
|
+
if (ch === '#' && afterSpace) {
|
|
61
|
+
result += wrap('sh-comment', line.slice(i));
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Double-quoted string
|
|
66
|
+
if (ch === '"') {
|
|
67
|
+
var end = i + 1;
|
|
68
|
+
while (end < len && line[end] !== '"') {
|
|
69
|
+
if (line[end] === '\\' && end + 1 < len) end += 2;
|
|
70
|
+
else end++;
|
|
71
|
+
}
|
|
72
|
+
if (end < len) end++;
|
|
73
|
+
result += wrap('sh-string', line.slice(i, end));
|
|
74
|
+
i = end;
|
|
75
|
+
afterSpace = false;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Single-quoted string
|
|
80
|
+
if (ch === "'") {
|
|
81
|
+
var end = i + 1;
|
|
82
|
+
while (end < len && line[end] !== "'") end++;
|
|
83
|
+
if (end < len) end++;
|
|
84
|
+
result += wrap('sh-string', line.slice(i, end));
|
|
85
|
+
i = end;
|
|
86
|
+
afterSpace = false;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Environment variable (ALLCAPS=)
|
|
91
|
+
if (afterSpace && /[A-Z]/.test(ch)) {
|
|
92
|
+
var match = line.slice(i).match(/^[A-Z][A-Z0-9_]*=/);
|
|
93
|
+
if (match) {
|
|
94
|
+
result += wrap('sh-envvar', match[0]);
|
|
95
|
+
i += match[0].length;
|
|
96
|
+
// Read unquoted value
|
|
97
|
+
var valEnd = i;
|
|
98
|
+
while (valEnd < len && line[valEnd] !== ' ' && line[valEnd] !== '\t' && line[valEnd] !== '"' && line[valEnd] !== "'") valEnd++;
|
|
99
|
+
if (valEnd > i) {
|
|
100
|
+
result += escapeHtml(line.slice(i, valEnd));
|
|
101
|
+
i = valEnd;
|
|
102
|
+
}
|
|
103
|
+
afterSpace = false;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Option (must be after whitespace)
|
|
109
|
+
if (ch === '-' && afterSpace) {
|
|
110
|
+
var match = line.slice(i).match(/^--?[a-zA-Z0-9_-]+(=[^"'\s]*)?/);
|
|
111
|
+
if (match) {
|
|
112
|
+
result += wrap('sh-option', match[0]);
|
|
113
|
+
i += match[0].length;
|
|
114
|
+
afterSpace = false;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Command (first word: regular, ./path, ../path, ~/path, /abs/path, @scope/pkg)
|
|
120
|
+
if (!seenCommand && afterSpace) {
|
|
121
|
+
var isCmd = /[a-zA-Z0-9@~\/]/.test(ch) ||
|
|
122
|
+
(ch === '.' && (line[i + 1] === '/' || (line[i + 1] === '.' && line[i + 2] === '/')));
|
|
123
|
+
if (isCmd) {
|
|
124
|
+
var end = i;
|
|
125
|
+
while (end < len && line[end] !== ' ' && line[end] !== '\t') end++;
|
|
126
|
+
result += wrap('sh-command', line.slice(i, end));
|
|
127
|
+
i = end;
|
|
128
|
+
seenCommand = true;
|
|
129
|
+
afterSpace = false;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Everything else
|
|
135
|
+
result += escapeHtml(ch);
|
|
136
|
+
i++;
|
|
137
|
+
afterSpace = false;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function highlightShell(code) {
|
|
144
|
+
return code.split('\n').map(highlightLine).join('\n');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function initHighlighting() {
|
|
148
|
+
var selectors = [
|
|
149
|
+
'pre.bash', 'pre.sh', 'pre.shell', 'pre.console',
|
|
150
|
+
'pre[data-language="bash"]', 'pre[data-language="sh"]',
|
|
151
|
+
'pre[data-language="shell"]', 'pre[data-language="console"]'
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
var blocks = document.querySelectorAll(selectors.join(', '));
|
|
155
|
+
blocks.forEach(function(block) {
|
|
156
|
+
if (block.getAttribute('data-highlighted') === 'true') return;
|
|
157
|
+
block.innerHTML = highlightShell(block.textContent);
|
|
158
|
+
block.setAttribute('data-highlighted', 'true');
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (document.readyState === 'loading') {
|
|
163
|
+
document.addEventListener('DOMContentLoaded', initHighlighting);
|
|
164
|
+
} else {
|
|
165
|
+
initHighlighting();
|
|
166
|
+
}
|
|
167
|
+
})();
|
|
@@ -276,7 +276,7 @@
|
|
|
276
276
|
* Initialize C syntax highlighting on page load
|
|
277
277
|
*/
|
|
278
278
|
function initHighlighting() {
|
|
279
|
-
const codeBlocks = document.querySelectorAll('pre
|
|
279
|
+
const codeBlocks = document.querySelectorAll('pre.c');
|
|
280
280
|
|
|
281
281
|
codeBlocks.forEach(block => {
|
|
282
282
|
if (block.getAttribute('data-highlighted') === 'true') {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
SearchController = function(data, input, result) {
|
|
2
2
|
this.data = data;
|
|
3
3
|
this.input = input;
|
|
4
4
|
this.result = result;
|
|
5
5
|
|
|
6
6
|
this.current = null;
|
|
7
7
|
this.view = this.result.parentNode;
|
|
8
|
-
this.
|
|
8
|
+
this.ranker = new SearchRanker(data.index);
|
|
9
9
|
this.init();
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
SearchController.prototype = Object.assign({}, SearchNavigation, new function() {
|
|
13
13
|
var suid = 1;
|
|
14
14
|
|
|
15
15
|
this.init = function() {
|
|
@@ -25,7 +25,7 @@ Search.prototype = Object.assign({}, Navigation, new function() {
|
|
|
25
25
|
this.input.addEventListener('keyup', observer);
|
|
26
26
|
this.input.addEventListener('click', observer); // mac's clear field
|
|
27
27
|
|
|
28
|
-
this.
|
|
28
|
+
this.ranker.ready(function(results, isLast) {
|
|
29
29
|
_this.addResults(results, isLast);
|
|
30
30
|
})
|
|
31
31
|
|
|
@@ -36,7 +36,7 @@ Search.prototype = Object.assign({}, Navigation, new function() {
|
|
|
36
36
|
this.search = function(value, selectFirstMatch) {
|
|
37
37
|
this.selectFirstMatch = selectFirstMatch;
|
|
38
38
|
|
|
39
|
-
value = value.trim()
|
|
39
|
+
value = value.trim();
|
|
40
40
|
if (value) {
|
|
41
41
|
this.setNavigationActive(true);
|
|
42
42
|
} else {
|
|
@@ -53,7 +53,7 @@ Search.prototype = Object.assign({}, Navigation, new function() {
|
|
|
53
53
|
this.result.setAttribute('aria-busy', 'true');
|
|
54
54
|
this.result.setAttribute('aria-expanded', 'true');
|
|
55
55
|
this.firstRun = true;
|
|
56
|
-
this.
|
|
56
|
+
this.ranker.find(value);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
@@ -96,7 +96,7 @@ Search.prototype = Object.assign({}, Navigation, new function() {
|
|
|
96
96
|
this.current.classList.remove('search-selected');
|
|
97
97
|
next.classList.add('search-selected');
|
|
98
98
|
this.input.setAttribute('aria-activedescendant', next.getAttribute('id'));
|
|
99
|
-
this.
|
|
99
|
+
this.scrollInElement(next, this.result);
|
|
100
100
|
this.current = next;
|
|
101
101
|
this.input.value = next.firstChild.firstChild.text;
|
|
102
102
|
this.input.select();
|
|
@@ -116,5 +116,14 @@ Search.prototype = Object.assign({}, Navigation, new function() {
|
|
|
116
116
|
});
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
this.hide = function() {
|
|
120
|
+
this.result.setAttribute('aria-expanded', 'false');
|
|
121
|
+
this.setNavigationActive(false);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.show = function() {
|
|
125
|
+
this.result.setAttribute('aria-expanded', 'true');
|
|
126
|
+
this.setNavigationActive(true);
|
|
127
|
+
}
|
|
119
128
|
});
|
|
120
129
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SearchNavigation allows movement using the arrow keys through the search results.
|
|
3
|
+
*
|
|
4
|
+
* When using this library you will need to set scrollIntoView to the
|
|
5
|
+
* appropriate function for your layout. Use scrollInWindow if the container
|
|
6
|
+
* is not scrollable and scrollInElement if the container is a separate
|
|
7
|
+
* scrolling region.
|
|
8
|
+
*/
|
|
9
|
+
SearchNavigation = new function() {
|
|
10
|
+
this.initNavigation = function() {
|
|
11
|
+
var _this = this;
|
|
12
|
+
|
|
13
|
+
document.addEventListener('keydown', function(e) {
|
|
14
|
+
_this.onkeydown(e);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
this.navigationActive = true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
this.setNavigationActive = function(state) {
|
|
21
|
+
this.navigationActive = state;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
this.onkeydown = function(e) {
|
|
25
|
+
if (!this.navigationActive) return;
|
|
26
|
+
switch(e.key) {
|
|
27
|
+
case 'ArrowLeft':
|
|
28
|
+
if (this.moveLeft()) e.preventDefault();
|
|
29
|
+
break;
|
|
30
|
+
case 'ArrowUp':
|
|
31
|
+
if (e.key == 'ArrowUp' || e.ctrlKey) {
|
|
32
|
+
if (this.moveUp()) e.preventDefault();
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
case 'ArrowRight':
|
|
36
|
+
if (this.moveRight()) e.preventDefault();
|
|
37
|
+
break;
|
|
38
|
+
case 'ArrowDown':
|
|
39
|
+
if (e.key == 'ArrowDown' || e.ctrlKey) {
|
|
40
|
+
if (this.moveDown()) e.preventDefault();
|
|
41
|
+
}
|
|
42
|
+
break;
|
|
43
|
+
case 'Enter':
|
|
44
|
+
if (this.current) e.preventDefault();
|
|
45
|
+
this.select(this.current);
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
if (e.ctrlKey && e.shiftKey) this.select(this.current);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.moveRight = function() {
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this.moveLeft = function() {
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.move = function(isDown) {
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.moveUp = function() {
|
|
61
|
+
return this.move(false);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.moveDown = function() {
|
|
65
|
+
return this.move(true);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/*
|
|
69
|
+
* Scrolls to the given element in the scrollable element view.
|
|
70
|
+
*/
|
|
71
|
+
this.scrollInElement = function(element, view) {
|
|
72
|
+
var offset, viewHeight, viewScroll, height;
|
|
73
|
+
offset = element.offsetTop;
|
|
74
|
+
height = element.offsetHeight;
|
|
75
|
+
viewHeight = view.offsetHeight;
|
|
76
|
+
viewScroll = view.scrollTop;
|
|
77
|
+
|
|
78
|
+
if (offset - viewScroll + height > viewHeight) {
|
|
79
|
+
view.scrollTop = offset - viewHeight + height;
|
|
80
|
+
}
|
|
81
|
+
if (offset < viewScroll) {
|
|
82
|
+
view.scrollTop = offset;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/*
|
|
87
|
+
* Scrolls to the given element in the window. The second argument is
|
|
88
|
+
* ignored
|
|
89
|
+
*/
|
|
90
|
+
this.scrollInWindow = function(element, ignored) {
|
|
91
|
+
var offset, viewHeight, viewScroll, height;
|
|
92
|
+
offset = element.offsetTop;
|
|
93
|
+
height = element.offsetHeight;
|
|
94
|
+
viewHeight = window.innerHeight;
|
|
95
|
+
viewScroll = window.scrollY;
|
|
96
|
+
|
|
97
|
+
if (offset - viewScroll + height > viewHeight) {
|
|
98
|
+
window.scrollTo(window.scrollX, offset - viewHeight + height);
|
|
99
|
+
}
|
|
100
|
+
if (offset < viewScroll) {
|
|
101
|
+
window.scrollTo(window.scrollX, offset);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|