rdoc 6.15.0 → 7.0.1

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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +187 -0
  3. data/History.rdoc +1 -1
  4. data/LEGAL.rdoc +6 -0
  5. data/README.md +20 -3
  6. data/lib/rdoc/code_object/any_method.rb +15 -7
  7. data/lib/rdoc/code_object/class_module.rb +13 -0
  8. data/lib/rdoc/code_object/constant.rb +9 -0
  9. data/lib/rdoc/code_object/method_attr.rb +13 -1
  10. data/lib/rdoc/code_object/top_level.rb +31 -18
  11. data/lib/rdoc/comment.rb +190 -8
  12. data/lib/rdoc/generator/aliki.rb +183 -0
  13. data/lib/rdoc/generator/darkfish.rb +5 -1
  14. data/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +8 -0
  15. data/lib/rdoc/generator/template/aliki/_footer.rhtml +23 -0
  16. data/lib/rdoc/generator/template/aliki/_head.rhtml +158 -0
  17. data/lib/rdoc/generator/template/aliki/_header.rhtml +56 -0
  18. data/lib/rdoc/generator/template/aliki/_icons.rhtml +208 -0
  19. data/lib/rdoc/generator/template/aliki/_sidebar_ancestors.rhtml +16 -0
  20. data/lib/rdoc/generator/template/aliki/_sidebar_classes.rhtml +15 -0
  21. data/lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml +25 -0
  22. data/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +25 -0
  23. data/lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml +16 -0
  24. data/lib/rdoc/generator/template/aliki/_sidebar_methods.rhtml +41 -0
  25. data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +67 -0
  26. data/lib/rdoc/generator/template/aliki/_sidebar_search.rhtml +15 -0
  27. data/lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml +21 -0
  28. data/lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml +3 -0
  29. data/lib/rdoc/generator/template/aliki/class.rhtml +218 -0
  30. data/lib/rdoc/generator/template/aliki/css/rdoc.css +1944 -0
  31. data/lib/rdoc/generator/template/aliki/index.rhtml +22 -0
  32. data/lib/rdoc/generator/template/aliki/js/aliki.js +498 -0
  33. data/lib/rdoc/generator/template/aliki/js/c_highlighter.js +299 -0
  34. data/lib/rdoc/generator/template/aliki/js/search_controller.js +120 -0
  35. data/lib/rdoc/generator/template/aliki/js/search_navigation.js +105 -0
  36. data/lib/rdoc/generator/template/aliki/js/search_ranker.js +239 -0
  37. data/lib/rdoc/generator/template/aliki/js/theme-toggle.js +112 -0
  38. data/lib/rdoc/generator/template/aliki/page.rhtml +18 -0
  39. data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +14 -0
  40. data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +65 -0
  41. data/lib/rdoc/generator/template/darkfish/_footer.rhtml +3 -3
  42. data/lib/rdoc/generator/template/darkfish/_head.rhtml +14 -19
  43. data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +8 -8
  44. data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +8 -8
  45. data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +7 -6
  46. data/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml +6 -6
  47. data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +19 -19
  48. data/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml +2 -2
  49. data/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml +1 -0
  50. data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +3 -3
  51. data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +14 -14
  52. data/lib/rdoc/generator/template/darkfish/class.rhtml +62 -62
  53. data/lib/rdoc/generator/template/darkfish/index.rhtml +4 -3
  54. data/lib/rdoc/generator/template/darkfish/page.rhtml +2 -1
  55. data/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml +2 -1
  56. data/lib/rdoc/generator/template/darkfish/servlet_root.rhtml +19 -19
  57. data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +19 -17
  58. data/lib/rdoc/generator/template/json_index/js/searcher.js +43 -6
  59. data/lib/rdoc/generator.rb +1 -0
  60. data/lib/rdoc/markup/pre_process.rb +34 -10
  61. data/lib/rdoc/markup/to_ansi.rb +4 -0
  62. data/lib/rdoc/markup/to_bs.rb +4 -0
  63. data/lib/rdoc/markup/to_html.rb +6 -4
  64. data/lib/rdoc/markup/to_rdoc.rb +11 -3
  65. data/lib/rdoc/options.rb +21 -10
  66. data/lib/rdoc/parser/c.rb +15 -46
  67. data/lib/rdoc/parser/prism_ruby.rb +121 -113
  68. data/lib/rdoc/parser/ruby.rb +8 -8
  69. data/lib/rdoc/parser/ruby_tools.rb +5 -7
  70. data/lib/rdoc/parser/simple.rb +4 -21
  71. data/lib/rdoc/rdoc.rb +1 -0
  72. data/lib/rdoc/rubygems_hook.rb +3 -3
  73. data/lib/rdoc/text.rb +1 -1
  74. data/lib/rdoc/token_stream.rb +13 -1
  75. data/lib/rdoc/tom_doc.rb +1 -1
  76. data/lib/rdoc/version.rb +1 -1
  77. data/rdoc.gemspec +1 -1
  78. metadata +33 -5
  79. data/CONTRIBUTING.rdoc +0 -219
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Client-side C syntax highlighter for RDoc
3
+ */
4
+
5
+ (function() {
6
+ 'use strict';
7
+
8
+ // C control flow and storage class keywords
9
+ const C_KEYWORDS = new Set([
10
+ 'auto', 'break', 'case', 'continue', 'default', 'do', 'else', 'extern',
11
+ 'for', 'goto', 'if', 'inline', 'register', 'return', 'sizeof', 'static',
12
+ 'switch', 'while',
13
+ '_Alignas', '_Alignof', '_Generic', '_Noreturn', '_Static_assert', '_Thread_local'
14
+ ]);
15
+
16
+ // C type keywords and type qualifiers
17
+ const C_TYPE_KEYWORDS = new Set([
18
+ 'bool', 'char', 'const', 'double', 'enum', 'float', 'int', 'long',
19
+ 'restrict', 'short', 'signed', 'struct', 'typedef', 'union', 'unsigned',
20
+ 'void', 'volatile', '_Atomic', '_Bool', '_Complex', '_Imaginary'
21
+ ]);
22
+
23
+ // Library-defined types (typedef'd in headers, not language keywords)
24
+ // Includes: Ruby C API types (VALUE, ID), POSIX types (size_t, ssize_t),
25
+ // fixed-width integer types (uint32_t, int64_t), and standard I/O types (FILE)
26
+ const C_TYPES = new Set([
27
+ 'VALUE', 'ID', 'size_t', 'ssize_t', 'ptrdiff_t', 'uintptr_t', 'intptr_t',
28
+ 'uint8_t', 'uint16_t', 'uint32_t', 'uint64_t',
29
+ 'int8_t', 'int16_t', 'int32_t', 'int64_t',
30
+ 'FILE', 'DIR', 'va_list'
31
+ ]);
32
+
33
+ // Common Ruby VALUE macros and boolean literals
34
+ const RUBY_MACROS = new Set([
35
+ 'Qtrue', 'Qfalse', 'Qnil', 'Qundef', 'NULL', 'TRUE', 'FALSE', 'true', 'false'
36
+ ]);
37
+
38
+ const OPERATORS = new Set([
39
+ '==', '!=', '<=', '>=', '&&', '||', '<<', '>>', '++', '--',
40
+ '+=', '-=', '*=', '/=', '%=', '&=', '|=', '^=', '->',
41
+ '+', '-', '*', '/', '%', '<', '>', '=', '!', '&', '|', '^', '~'
42
+ ]);
43
+
44
+ // Single character that can start an operator
45
+ const OPERATOR_CHARS = new Set('+-*/%<>=!&|^~');
46
+
47
+ function isMacro(word) {
48
+ return RUBY_MACROS.has(word) || /^[A-Z][A-Z0-9_]*$/.test(word);
49
+ }
50
+
51
+ function isType(word) {
52
+ return C_TYPE_KEYWORDS.has(word) || C_TYPES.has(word) || /_t$/.test(word);
53
+ }
54
+
55
+ /**
56
+ * Escape HTML special characters
57
+ */
58
+ function escapeHtml(text) {
59
+ return text
60
+ .replace(/&/g, '&amp;')
61
+ .replace(/</g, '&lt;')
62
+ .replace(/>/g, '&gt;')
63
+ .replace(/"/g, '&quot;')
64
+ .replace(/'/g, '&#39;');
65
+ }
66
+
67
+ /**
68
+ * Check if position is at line start (only whitespace before it)
69
+ */
70
+ function isLineStart(code, pos) {
71
+ if (pos === 0) return true;
72
+ for (let i = pos - 1; i >= 0; i--) {
73
+ const ch = code[i];
74
+ if (ch === '\n') return true;
75
+ if (ch !== ' ' && ch !== '\t') return false;
76
+ }
77
+ return true;
78
+ }
79
+
80
+ /**
81
+ * Highlight C source code
82
+ */
83
+ function highlightC(code) {
84
+ const tokens = [];
85
+ let i = 0;
86
+ const len = code.length;
87
+
88
+ while (i < len) {
89
+ const char = code[i];
90
+
91
+ // Multi-line comment
92
+ if (char === '/' && code[i + 1] === '*') {
93
+ let end = code.indexOf('*/', i + 2);
94
+ end = (end === -1) ? len : end + 2;
95
+ const comment = code.substring(i, end);
96
+ tokens.push('<span class="c-comment">', escapeHtml(comment), '</span>');
97
+ i = end;
98
+ continue;
99
+ }
100
+
101
+ // Single-line comment
102
+ if (char === '/' && code[i + 1] === '/') {
103
+ const end = code.indexOf('\n', i);
104
+ const commentEnd = (end === -1) ? len : end;
105
+ const comment = code.substring(i, commentEnd);
106
+ tokens.push('<span class="c-comment">', escapeHtml(comment), '</span>');
107
+ i = commentEnd;
108
+ continue;
109
+ }
110
+
111
+ // Preprocessor directive (must be at line start)
112
+ if (char === '#' && isLineStart(code, i)) {
113
+ let end = i + 1;
114
+ while (end < len && code[end] !== '\n') {
115
+ if (code[end] === '\\' && end + 1 < len && code[end + 1] === '\n') {
116
+ end += 2; // Handle line continuation
117
+ } else {
118
+ end++;
119
+ }
120
+ }
121
+ const preprocessor = code.substring(i, end);
122
+ tokens.push('<span class="c-preprocessor">', escapeHtml(preprocessor), '</span>');
123
+ i = end;
124
+ continue;
125
+ }
126
+
127
+ // String literal
128
+ if (char === '"') {
129
+ let end = i + 1;
130
+ while (end < len && code[end] !== '"') {
131
+ if (code[end] === '\\' && end + 1 < len) {
132
+ end += 2; // Skip escaped character
133
+ } else {
134
+ end++;
135
+ }
136
+ }
137
+ if (end < len) end++; // Include closing quote
138
+ const string = code.substring(i, end);
139
+ tokens.push('<span class="c-string">', escapeHtml(string), '</span>');
140
+ i = end;
141
+ continue;
142
+ }
143
+
144
+ // Character literal
145
+ if (char === "'") {
146
+ let end = i + 1;
147
+ // Handle escape sequences like '\n', '\\', '\''
148
+ if (end < len && code[end] === '\\' && end + 1 < len) {
149
+ end += 2; // Skip backslash and escaped char
150
+ } else if (end < len) {
151
+ end++; // Single character
152
+ }
153
+ if (end < len && code[end] === "'") end++; // Closing quote
154
+ const charLit = code.substring(i, end);
155
+ tokens.push('<span class="c-value">', escapeHtml(charLit), '</span>');
156
+ i = end;
157
+ continue;
158
+ }
159
+
160
+ // Number (integer or float)
161
+ if (char >= '0' && char <= '9') {
162
+ let end = i;
163
+
164
+ // Hexadecimal
165
+ if (char === '0' && (code[i + 1] === 'x' || code[i + 1] === 'X')) {
166
+ end = i + 2;
167
+ while (end < len) {
168
+ const ch = code[end];
169
+ if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
170
+ end++;
171
+ } else {
172
+ break;
173
+ }
174
+ }
175
+ }
176
+ // Octal
177
+ else if (char === '0' && code[i + 1] >= '0' && code[i + 1] <= '7') {
178
+ end = i + 1;
179
+ while (end < len && code[end] >= '0' && code[end] <= '7') end++;
180
+ }
181
+ // Decimal/Float
182
+ else {
183
+ while (end < len) {
184
+ const ch = code[end];
185
+ if ((ch >= '0' && ch <= '9') || ch === '.') {
186
+ end++;
187
+ } else {
188
+ break;
189
+ }
190
+ }
191
+ // Scientific notation
192
+ if (end < len && (code[end] === 'e' || code[end] === 'E')) {
193
+ end++;
194
+ if (end < len && (code[end] === '+' || code[end] === '-')) end++;
195
+ while (end < len && code[end] >= '0' && code[end] <= '9') end++;
196
+ }
197
+ }
198
+
199
+ // Suffix (u, l, f, etc.)
200
+ while (end < len) {
201
+ const ch = code[end];
202
+ if (ch === 'u' || ch === 'U' || ch === 'l' || ch === 'L' || ch === 'f' || ch === 'F') {
203
+ end++;
204
+ } else {
205
+ break;
206
+ }
207
+ }
208
+
209
+ const number = code.substring(i, end);
210
+ tokens.push('<span class="c-value">', escapeHtml(number), '</span>');
211
+ i = end;
212
+ continue;
213
+ }
214
+
215
+ // Identifier or keyword
216
+ if ((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || char === '_') {
217
+ let end = i + 1;
218
+ while (end < len) {
219
+ const ch = code[end];
220
+ if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
221
+ (ch >= '0' && ch <= '9') || ch === '_') {
222
+ end++;
223
+ } else {
224
+ break;
225
+ }
226
+ }
227
+ const word = code.substring(i, end);
228
+
229
+ if (C_KEYWORDS.has(word)) {
230
+ tokens.push('<span class="c-keyword">', escapeHtml(word), '</span>');
231
+ } else if (isType(word)) {
232
+ // Check types before macros (VALUE, ID are types, not macros)
233
+ tokens.push('<span class="c-type">', escapeHtml(word), '</span>');
234
+ } else if (isMacro(word)) {
235
+ tokens.push('<span class="c-macro">', escapeHtml(word), '</span>');
236
+ } else {
237
+ // Check if followed by '(' -> function name
238
+ let nextCharIdx = end;
239
+ while (nextCharIdx < len && (code[nextCharIdx] === ' ' || code[nextCharIdx] === '\t')) {
240
+ nextCharIdx++;
241
+ }
242
+ if (nextCharIdx < len && code[nextCharIdx] === '(') {
243
+ tokens.push('<span class="c-function">', escapeHtml(word), '</span>');
244
+ } else {
245
+ tokens.push('<span class="c-identifier">', escapeHtml(word), '</span>');
246
+ }
247
+ }
248
+ i = end;
249
+ continue;
250
+ }
251
+
252
+ // Operators
253
+ if (OPERATOR_CHARS.has(char)) {
254
+ let op = char;
255
+ // Check for two-character operators
256
+ if (i + 1 < len) {
257
+ const twoChar = char + code[i + 1];
258
+ if (OPERATORS.has(twoChar)) {
259
+ op = twoChar;
260
+ }
261
+ }
262
+ tokens.push('<span class="c-operator">', escapeHtml(op), '</span>');
263
+ i += op.length;
264
+ continue;
265
+ }
266
+
267
+ // Everything else (punctuation, whitespace)
268
+ tokens.push(escapeHtml(char));
269
+ i++;
270
+ }
271
+
272
+ return tokens.join('');
273
+ }
274
+
275
+ /**
276
+ * Initialize C syntax highlighting on page load
277
+ */
278
+ function initHighlighting() {
279
+ const codeBlocks = document.querySelectorAll('pre[data-language="c"]');
280
+
281
+ codeBlocks.forEach(block => {
282
+ if (block.getAttribute('data-highlighted') === 'true') {
283
+ return;
284
+ }
285
+
286
+ const code = block.textContent;
287
+ const highlighted = highlightC(code);
288
+
289
+ block.innerHTML = highlighted;
290
+ block.setAttribute('data-highlighted', 'true');
291
+ });
292
+ }
293
+
294
+ if (document.readyState === 'loading') {
295
+ document.addEventListener('DOMContentLoaded', initHighlighting);
296
+ } else {
297
+ initHighlighting();
298
+ }
299
+ })();
@@ -0,0 +1,120 @@
1
+ SearchController = function(data, input, result) {
2
+ this.data = data;
3
+ this.input = input;
4
+ this.result = result;
5
+
6
+ this.current = null;
7
+ this.view = this.result.parentNode;
8
+ this.ranker = new SearchRanker(data.index);
9
+ this.init();
10
+ }
11
+
12
+ SearchController.prototype = Object.assign({}, SearchNavigation, new function() {
13
+ var suid = 1;
14
+
15
+ this.init = function() {
16
+ var _this = this;
17
+ var observer = function(e) {
18
+ switch(e.key) {
19
+ case 'ArrowUp':
20
+ case 'ArrowDown':
21
+ return;
22
+ }
23
+ _this.search(_this.input.value);
24
+ };
25
+ this.input.addEventListener('keyup', observer);
26
+ this.input.addEventListener('click', observer); // mac's clear field
27
+
28
+ this.ranker.ready(function(results, isLast) {
29
+ _this.addResults(results, isLast);
30
+ })
31
+
32
+ this.initNavigation();
33
+ this.setNavigationActive(false);
34
+ }
35
+
36
+ this.search = function(value, selectFirstMatch) {
37
+ this.selectFirstMatch = selectFirstMatch;
38
+
39
+ value = value.trim();
40
+ if (value) {
41
+ this.setNavigationActive(true);
42
+ } else {
43
+ this.setNavigationActive(false);
44
+ }
45
+
46
+ if (value == '') {
47
+ this.lastQuery = value;
48
+ this.result.innerHTML = '';
49
+ this.result.setAttribute('aria-expanded', 'false');
50
+ this.setNavigationActive(false);
51
+ } else if (value != this.lastQuery) {
52
+ this.lastQuery = value;
53
+ this.result.setAttribute('aria-busy', 'true');
54
+ this.result.setAttribute('aria-expanded', 'true');
55
+ this.firstRun = true;
56
+ this.ranker.find(value);
57
+ }
58
+ }
59
+
60
+ this.addResults = function(results, isLast) {
61
+ var target = this.result;
62
+ if (this.firstRun && (results.length > 0 || isLast)) {
63
+ this.current = null;
64
+ this.result.innerHTML = '';
65
+ }
66
+
67
+ for (var i=0, l = results.length; i < l; i++) {
68
+ var item = this.renderItem.call(this, results[i]);
69
+ item.setAttribute('id', 'search-result-' + target.childElementCount);
70
+ target.appendChild(item);
71
+ };
72
+
73
+ if (this.firstRun && results.length > 0) {
74
+ this.firstRun = false;
75
+ this.current = target.firstChild;
76
+ this.current.classList.add('search-selected');
77
+ }
78
+ //TODO: ECMAScript
79
+ //if (jQuery.browser.msie) this.$element[0].className += '';
80
+
81
+ if (this.selectFirstMatch && this.current) {
82
+ this.selectFirstMatch = false;
83
+ this.select(this.current);
84
+ }
85
+
86
+ if (isLast) {
87
+ this.selectFirstMatch = false;
88
+ this.result.setAttribute('aria-busy', 'false');
89
+ }
90
+ }
91
+
92
+ this.move = function(isDown) {
93
+ if (!this.current) return;
94
+ var next = isDown ? this.current.nextElementSibling : this.current.previousElementSibling;
95
+ if (next) {
96
+ this.current.classList.remove('search-selected');
97
+ next.classList.add('search-selected');
98
+ this.input.setAttribute('aria-activedescendant', next.getAttribute('id'));
99
+ this.scrollIntoView(next, this.view);
100
+ this.current = next;
101
+ this.input.value = next.firstChild.firstChild.text;
102
+ this.input.select();
103
+ }
104
+ return true;
105
+ }
106
+
107
+ this.hlt = function(html) {
108
+ return this.escapeHTML(html).
109
+ replace(/\u0001/g, '<em>').
110
+ replace(/\u0002/g, '</em>');
111
+ }
112
+
113
+ this.escapeHTML = function(html) {
114
+ return html.replace(/[&<>"`']/g, function(c) {
115
+ return '&#' + c.charCodeAt(0) + ';';
116
+ });
117
+ }
118
+
119
+ });
120
+
@@ -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
+