sdoc 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. data/lib/sdoc/generator.rb +34 -11
  2. data/lib/sdoc/generator/template/direct/_context.rhtml +1 -1
  3. data/lib/sdoc/generator/template/direct/_head.rhtml +7 -0
  4. data/lib/sdoc/generator/template/direct/class.rhtml +4 -5
  5. data/lib/sdoc/generator/template/direct/file.rhtml +4 -5
  6. data/lib/sdoc/generator/template/direct/index.rhtml +1 -2
  7. data/lib/sdoc/generator/template/direct/resources/css/github.css +129 -0
  8. data/lib/sdoc/generator/template/direct/resources/js/highlight.pack.js +1 -0
  9. data/lib/sdoc/generator/template/direct/resources/js/main.js +15 -13
  10. data/lib/sdoc/generator/template/direct/resources/panel/index.html +32 -31
  11. data/lib/sdoc/generator/template/direct/se_index.rhtml +8 -0
  12. data/sdoc.gemspec +2 -2
  13. metadata +8 -20
  14. data/lib/sdoc/generator/template/shtml/_context.rhtml +0 -163
  15. data/lib/sdoc/generator/template/shtml/class.rhtml +0 -46
  16. data/lib/sdoc/generator/template/shtml/file.rhtml +0 -37
  17. data/lib/sdoc/generator/template/shtml/index.rhtml +0 -14
  18. data/lib/sdoc/generator/template/shtml/resources/apple-touch-icon.png +0 -0
  19. data/lib/sdoc/generator/template/shtml/resources/css/main.css +0 -191
  20. data/lib/sdoc/generator/template/shtml/resources/css/panel.css +0 -383
  21. data/lib/sdoc/generator/template/shtml/resources/css/reset.css +0 -53
  22. data/lib/sdoc/generator/template/shtml/resources/favicon.ico +0 -0
  23. data/lib/sdoc/generator/template/shtml/resources/i/arrows.png +0 -0
  24. data/lib/sdoc/generator/template/shtml/resources/i/results_bg.png +0 -0
  25. data/lib/sdoc/generator/template/shtml/resources/i/tree_bg.png +0 -0
  26. data/lib/sdoc/generator/template/shtml/resources/js/jquery-1.3.2.min.js +0 -19
  27. data/lib/sdoc/generator/template/shtml/resources/js/main.js +0 -34
  28. data/lib/sdoc/generator/template/shtml/resources/js/searchdoc.js +0 -628
  29. data/lib/sdoc/generator/template/shtml/resources/panel/index.html +0 -71
@@ -1,34 +0,0 @@
1
- function toggleSource( id )
2
- {
3
- var elem
4
- var link
5
-
6
- if( document.getElementById )
7
- {
8
- elem = document.getElementById( id )
9
- link = document.getElementById( "l_" + id )
10
- }
11
- else if ( document.all )
12
- {
13
- elem = eval( "document.all." + id )
14
- link = eval( "document.all.l_" + id )
15
- }
16
- else
17
- return false;
18
-
19
- if( elem.style.display == "block" )
20
- {
21
- elem.style.display = "none"
22
- link.innerHTML = "show"
23
- }
24
- else
25
- {
26
- elem.style.display = "block"
27
- link.innerHTML = "hide"
28
- }
29
- }
30
-
31
- function openCode( url )
32
- {
33
- window.open( url, "SOURCE_CODE", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=480,width=750" ).focus();
34
- }
@@ -1,628 +0,0 @@
1
- Searchdoc = {};
2
-
3
- // navigation.js ------------------------------------------
4
-
5
- Searchdoc.Navigation = new function() {
6
- this.initNavigation = function() {
7
- var _this = this;
8
-
9
- $(document).keydown(function(e) {
10
- _this.onkeydown(e);
11
- }).keyup(function(e) {
12
- _this.onkeyup(e);
13
- });
14
-
15
- this.navigationActive = true;
16
- }
17
-
18
- this.setNavigationActive = function(state) {
19
- this.navigationActive = state;
20
- this.clearMoveTimeout();
21
- }
22
-
23
-
24
- this.onkeyup = function(e) {
25
- if (!this.navigationActive) return;
26
- switch(e.keyCode) {
27
- case 37: //Event.KEY_LEFT:
28
- case 38: //Event.KEY_UP:
29
- case 39: //Event.KEY_RIGHT:
30
- case 40: //Event.KEY_DOWN:
31
- case 73: // i - qwerty
32
- case 74: // j
33
- case 75: // k
34
- case 76: // l
35
- case 67: // c - dvorak
36
- case 72: // h
37
- case 84: // t
38
- case 78: // n
39
- this.clearMoveTimeout();
40
- break;
41
- }
42
- }
43
-
44
- this.onkeydown = function(e) {
45
- if (!this.navigationActive) return;
46
- switch(e.keyCode) {
47
- case 37: //Event.KEY_LEFT:
48
- case 74: // j (qwerty)
49
- case 72: // h (dvorak)
50
- if (this.moveLeft()) e.preventDefault();
51
- break;
52
- case 38: //Event.KEY_UP:
53
- case 73: // i (qwerty)
54
- case 67: // c (dvorak)
55
- if (e.keyCode == 38 || e.ctrlKey) {
56
- if (this.moveUp()) e.preventDefault();
57
- this.startMoveTimeout(false);
58
- }
59
- break;
60
- case 39: //Event.KEY_RIGHT:
61
- case 76: // l (qwerty)
62
- case 78: // n (dvorak)
63
- if (this.moveRight()) e.preventDefault();
64
- break;
65
- case 40: //Event.KEY_DOWN:
66
- case 75: // k (qwerty)
67
- case 84: // t (dvorak)
68
- if (e.keyCode == 40 || e.ctrlKey) {
69
- if (this.moveDown()) e.preventDefault();
70
- this.startMoveTimeout(true);
71
- }
72
- break;
73
- case 9: //Event.KEY_TAB:
74
- case 13: //Event.KEY_RETURN:
75
- if (this.$current) this.select(this.$current);
76
- break;
77
- }
78
- if (e.ctrlKey && e.shiftKey) this.select(this.$current);
79
- }
80
-
81
- this.clearMoveTimeout = function() {
82
- clearTimeout(this.moveTimeout);
83
- this.moveTimeout = null;
84
- }
85
-
86
- this.startMoveTimeout = function(isDown) {
87
- if (!$.browser.mozilla && !$.browser.opera) return;
88
- if (this.moveTimeout) this.clearMoveTimeout();
89
- var _this = this;
90
-
91
- var go = function() {
92
- if (!_this.moveTimeout) return;
93
- _this[isDown ? 'moveDown' : 'moveUp']();
94
- _this.moveTimout = setTimeout(go, 100);
95
- }
96
- this.moveTimeout = setTimeout(go, 200);
97
- }
98
-
99
- this.moveRight = function() {
100
- }
101
-
102
- this.moveLeft = function() {
103
- }
104
-
105
- this.move = function(isDown) {
106
- }
107
-
108
- this.moveUp = function() {
109
- return this.move(false);
110
- }
111
-
112
- this.moveDown = function() {
113
- return this.move(true);
114
- }
115
- }
116
-
117
-
118
- // scrollIntoView.js --------------------------------------
119
-
120
- function scrollIntoView(element, view) {
121
- var offset, viewHeight, viewScroll, height;
122
- offset = element.offsetTop;
123
- height = element.offsetHeight;
124
- viewHeight = view.offsetHeight;
125
- viewScroll = view.scrollTop;
126
- if (offset - viewScroll + height > viewHeight) {
127
- view.scrollTop = offset - viewHeight + height;
128
- }
129
- if (offset < viewScroll) {
130
- view.scrollTop = offset;
131
- }
132
- }
133
-
134
-
135
- // searcher.js --------------------------------------------
136
-
137
- Searchdoc.Searcher = function(data) {
138
- this.data = data;
139
- this.handlers = [];
140
- }
141
-
142
- Searchdoc.Searcher.prototype = new function() {
143
- var CHUNK_SIZE = 1000, // search is performed in chunks of 1000 for non-bloking user input
144
- MAX_RESULTS = 100, // do not try to find more than 100 results
145
- huid = 1, suid = 1,
146
- runs = 0;
147
-
148
-
149
- this.find = function(query) {
150
- var queries = splitQuery(query),
151
- regexps = buildRegexps(queries),
152
- highlighters = buildHilighters(queries),
153
- state = { from: 0, pass: 0, limit: MAX_RESULTS, n: suid++},
154
- _this = this;
155
- this.currentSuid = state.n;
156
-
157
- if (!query) return;
158
-
159
- var run = function() {
160
- // stop current search thread if new search started
161
- if (state.n != _this.currentSuid) return;
162
-
163
- var results = performSearch(_this.data, regexps, queries, highlighters, state),
164
- hasMore = (state.limit > 0 && state.pass < 3);
165
-
166
- triggerResults.call(_this, results, !hasMore);
167
- if (hasMore) {
168
- setTimeout(run, 2);
169
- }
170
- runs++;
171
- };
172
- runs = 0;
173
-
174
- // start search thread
175
- run();
176
- }
177
-
178
- /* ----- Events ------ */
179
- this.ready = function(fn) {
180
- fn.huid = huid;
181
- this.handlers.push(fn);
182
- }
183
-
184
- /* ----- Utilities ------ */
185
- function splitQuery(query) {
186
- return jQuery.grep(query.split(/(\s+|\(\)?)/), function(string) { return string.match(/\S/) });
187
- }
188
-
189
- function buildRegexps(queries) {
190
- return jQuery.map(queries, function(query) { return new RegExp(query.replace(/(.)/g, '([$1])([^$1]*?)'), 'i') });
191
- }
192
-
193
- function buildHilighters(queries) {
194
- return jQuery.map(queries, function(query) {
195
- return jQuery.map( query.split(''), function(l, i){ return '\u0001$' + (i*2+1) + '\u0002$' + (i*2+2) } ).join('')
196
- });
197
- }
198
-
199
- // function longMatchRegexp(index, longIndex, regexps) {
200
- // for (var i = regexps.length - 1; i >= 0; i--){
201
- // if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) return false;
202
- // };
203
- // return true;
204
- // }
205
-
206
-
207
- /* ----- Mathchers ------ */
208
- function matchPass1(index, longIndex, queries, regexps) {
209
- if (index.indexOf(queries[0]) != 0) return false;
210
- for (var i=1, l = regexps.length; i < l; i++) {
211
- if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) return false;
212
- };
213
- return true;
214
- }
215
-
216
- function matchPass2(index, longIndex, queries, regexps) {
217
- if (index.indexOf(queries[0]) == -1) return false;
218
- for (var i=1, l = regexps.length; i < l; i++) {
219
- if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) return false;
220
- };
221
- return true;
222
- }
223
-
224
- function matchPassRegexp(index, longIndex, queries, regexps) {
225
- if (!index.match(regexps[0])) return false;
226
- for (var i=1, l = regexps.length; i < l; i++) {
227
- if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) return false;
228
- };
229
- return true;
230
- }
231
-
232
-
233
- /* ----- Highlighters ------ */
234
- function highlightRegexp(info, queries, regexps, highlighters) {
235
- var result = createResult(info);
236
- for (var i=0, l = regexps.length; i < l; i++) {
237
- result.title = result.title.replace(regexps[i], highlighters[i]);
238
- if (i > 0)
239
- result.namespace = result.namespace.replace(regexps[i], highlighters[i]);
240
- };
241
- return result;
242
- }
243
-
244
- function hltSubstring(string, pos, length) {
245
- return string.substring(0, pos) + '\u0001' + string.substring(pos, pos + length) + '\u0002' + string.substring(pos + length);
246
- }
247
-
248
- function highlightQuery(info, queries, regexps, highlighters) {
249
- var result = createResult(info), pos = 0, lcTitle = result.title.toLowerCase();
250
- pos = lcTitle.indexOf(queries[0]);
251
- if (pos != -1) {
252
- result.title = hltSubstring(result.title, pos, queries[0].length);
253
- }
254
- for (var i=1, l = regexps.length; i < l; i++) {
255
- result.title = result.title.replace(regexps[i], highlighters[i]);
256
- result.namespace = result.namespace.replace(regexps[i], highlighters[i]);
257
- };
258
- return result;
259
- }
260
-
261
- function createResult(info) {
262
- var result = {};
263
- result.title = info[0];
264
- result.namespace = info[1];
265
- result.path = info[2];
266
- result.params = info[3];
267
- result.snippet = info[4];
268
- result.badge = info[6];
269
- return result;
270
- }
271
-
272
- /* ----- Searching ------ */
273
- function performSearch(data, regexps, queries, highlighters, state) {
274
- var searchIndex = data.searchIndex, // search by title first and then by source
275
- longSearchIndex = data.longSearchIndex,
276
- info = data.info,
277
- result = [],
278
- i = state.from,
279
- l = searchIndex.length,
280
- togo = CHUNK_SIZE,
281
- matchFunc, hltFunc;
282
-
283
- while (state.pass < 3 && state.limit > 0 && togo > 0) {
284
- if (state.pass == 0) {
285
- matchFunc = matchPass1;
286
- hltFunc = highlightQuery;
287
- } else if (state.pass == 1) {
288
- matchFunc = matchPass2;
289
- hltFunc = highlightQuery;
290
- } else if (state.pass == 2) {
291
- matchFunc = matchPassRegexp;
292
- hltFunc = highlightRegexp;
293
- }
294
-
295
- for (; togo > 0 && i < l && state.limit > 0; i++, togo--) {
296
- if (info[i].n == state.n) continue;
297
- if (matchFunc(searchIndex[i], longSearchIndex[i], queries, regexps)) {
298
- info[i].n = state.n;
299
- result.push(hltFunc(info[i], queries, regexps, highlighters));
300
- state.limit--;
301
- }
302
- };
303
- if (searchIndex.length <= i) {
304
- state.pass++;
305
- i = state.from = 0;
306
- } else {
307
- state.from = i;
308
- }
309
- }
310
- return result;
311
- }
312
-
313
- function triggerResults(results, isLast) {
314
- jQuery.each(this.handlers, function(i, fn) { fn.call(this, results, isLast) })
315
- }
316
- }
317
-
318
-
319
-
320
-
321
- // panel.js -----------------------------------------------
322
-
323
- Searchdoc.Panel = function(element, data, tree, frame) {
324
- this.$element = $(element);
325
- this.$input = $('input', element).eq(0);
326
- this.$result = $('.result ul', element).eq(0);
327
- this.frame = frame;
328
- this.$current = null;
329
- this.$view = this.$result.parent();
330
- this.data = data;
331
- this.searcher = new Searchdoc.Searcher(data.index);
332
- this.tree = new Searchdoc.Tree($('.tree', element), tree, this);
333
- this.init();
334
- }
335
-
336
- Searchdoc.Panel.prototype = $.extend({}, Searchdoc.Navigation, new function() {
337
- var suid = 1;
338
-
339
- this.init = function() {
340
- var _this = this;
341
- var observer = function() {
342
- _this.search(_this.$input[0].value);
343
- };
344
- this.$input.keyup(observer);
345
- this.$input.click(observer); // mac's clear field
346
-
347
- this.searcher.ready(function(results, isLast) {
348
- _this.addResults(results, isLast);
349
- })
350
-
351
- this.$result.click(function(e) {
352
- _this.$current.removeClass('current');
353
- _this.$current = $(e.target).closest('li').addClass('current');
354
- _this.select();
355
- _this.$input.focus();
356
- });
357
-
358
- this.initNavigation();
359
- this.setNavigationActive(false);
360
- }
361
-
362
- this.search = function(value, selectFirstMatch) {
363
- value = jQuery.trim(value).toLowerCase();
364
- this.selectFirstMatch = selectFirstMatch;
365
- if (value) {
366
- this.$element.removeClass('panel_tree').addClass('panel_results');
367
- this.tree.setNavigationActive(false);
368
- this.setNavigationActive(true);
369
- } else {
370
- this.$element.addClass('panel_tree').removeClass('panel_results');
371
- this.tree.setNavigationActive(true);
372
- this.setNavigationActive(false);
373
- }
374
- if (value != this.lastQuery) {
375
- this.lastQuery = value;
376
- this.firstRun = true;
377
- this.searcher.find(value);
378
- }
379
- }
380
-
381
- this.addResults = function(results, isLast) {
382
- var target = this.$result.get(0);
383
- if (this.firstRun && (results.length > 0 || isLast)) {
384
- this.$current = null;
385
- this.$result.empty();
386
- }
387
- for (var i=0, l = results.length; i < l; i++) {
388
- target.appendChild(renderItem.call(this, results[i]));
389
- };
390
- if (this.firstRun && results.length > 0) {
391
- this.firstRun = false;
392
- this.$current = $(target.firstChild);
393
- this.$current.addClass('current');
394
- if (this.selectFirstMatch) this.select();
395
- scrollIntoView(this.$current[0], this.$view[0])
396
- }
397
- if (jQuery.browser.msie) this.$element[0].className += '';
398
- }
399
-
400
- this.open = function(src) {
401
- this.frame.location.href = '../' + src;
402
- if (this.frame.highlight) this.frame.highlight(src);
403
- }
404
-
405
- this.select = function() {
406
- this.open(this.$current.data('path'));
407
- }
408
-
409
- this.move = function(isDown) {
410
- if (!this.$current) return;
411
- var $next = this.$current[isDown ? 'next' : 'prev']();
412
- if ($next.length) {
413
- this.$current.removeClass('current');
414
- $next.addClass('current');
415
- scrollIntoView($next[0], this.$view[0]);
416
- this.$current = $next;
417
- }
418
- return true;
419
- }
420
-
421
- function renderItem(result) {
422
- var li = document.createElement('li'),
423
- html = '', badge = result.badge;
424
- html += '<h1>' + hlt(result.title);
425
- if (result.params) html += '<i>' + result.params + '</i>';
426
- html += '</h1>';
427
- html += '<p>';
428
- if (typeof badge != 'undefined') {
429
- html += '<span class="badge badge_' + (badge % 6 + 1) + '">' + escapeHTML(this.data.badges[badge] || 'unknown') + '</span>';
430
- }
431
- html += hlt(result.namespace) + '</p>';
432
- if (result.snippet) html += '<p class="snippet">' + escapeHTML(result.snippet) + '</p>';
433
- li.innerHTML = html;
434
- jQuery.data(li, 'path', result.path);
435
- return li;
436
- }
437
-
438
- function hlt(html) {
439
- return escapeHTML(html).replace(/\u0001/g, '<b>').replace(/\u0002/g, '</b>')
440
- }
441
-
442
- function escapeHTML(html) {
443
- return html.replace(/[&<>]/g, function(c) {
444
- return '&#' + c.charCodeAt(0) + ';';
445
- });
446
- }
447
-
448
- });
449
-
450
- // tree.js ------------------------------------------------
451
-
452
- Searchdoc.Tree = function(element, tree, panel) {
453
- this.$element = $(element);
454
- this.$list = $('ul', element);
455
- this.tree = tree;
456
- this.panel = panel;
457
- this.init();
458
- }
459
-
460
- Searchdoc.Tree.prototype = $.extend({}, Searchdoc.Navigation, new function() {
461
- this.init = function() {
462
- var stopper = document.createElement('li');
463
- stopper.className = 'stopper';
464
- this.$list[0].appendChild(stopper);
465
- for (var i=0, l = this.tree.length; i < l; i++) {
466
- buildAndAppendItem.call(this, this.tree[i], 0, stopper);
467
- };
468
- var _this = this;
469
- this.$list.click(function(e) {
470
- var $target = $(e.target),
471
- $li = $target.closest('li');
472
- if ($target.hasClass('icon')) {
473
- _this.toggle($li);
474
- } else {
475
- _this.select($li);
476
- }
477
- })
478
-
479
- this.initNavigation();
480
- if (jQuery.browser.msie) document.body.className += '';
481
- }
482
-
483
- this.select = function($li) {
484
- this.highlight($li);
485
- var path = $li[0].searchdoc_tree_data.path;
486
- if (path) this.panel.open(path);
487
- }
488
-
489
- this.highlight = function($li) {
490
- if (this.$current) this.$current.removeClass('current');
491
- this.$current = $li.addClass('current');
492
- }
493
-
494
- this.toggle = function($li) {
495
- var closed = !$li.hasClass('closed'),
496
- children = $li[0].searchdoc_tree_data.children;
497
- $li.toggleClass('closed');
498
- for (var i=0, l = children.length; i < l; i++) {
499
- toggleVis.call(this, $(children[i].li), !closed);
500
- };
501
- }
502
-
503
- this.moveRight = function() {
504
- if (!this.$current) {
505
- this.highlight(this.$list.find('li:first'));
506
- return;
507
- }
508
- if (this.$current.hasClass('closed')) {
509
- this.toggle(this.$current);
510
- }
511
- }
512
-
513
- this.moveLeft = function() {
514
- if (!this.$current) {
515
- this.highlight(this.$list.find('li:first'));
516
- return;
517
- }
518
- if (!this.$current.hasClass('closed')) {
519
- this.toggle(this.$current);
520
- } else {
521
- var level = this.$current[0].searchdoc_tree_data.level;
522
- if (level == 0) return;
523
- var $next = this.$current.prevAll('li.level_' + (level - 1) + ':visible:first');
524
- this.$current.removeClass('current');
525
- $next.addClass('current');
526
- scrollIntoView($next[0], this.$element[0]);
527
- this.$current = $next;
528
- }
529
- }
530
-
531
- this.move = function(isDown) {
532
- if (!this.$current) {
533
- this.highlight(this.$list.find('li:first'));
534
- return true;
535
- }
536
- var next = this.$current[0];
537
- if (isDown) {
538
- do {
539
- next = next.nextSibling;
540
- if (next && next.style && next.style.display != 'none') break;
541
- } while(next);
542
- } else {
543
- do {
544
- next = next.previousSibling;
545
- if (next && next.style && next.style.display != 'none') break;
546
- } while(next);
547
- }
548
- if (next && next.className.indexOf('stopper') == -1) {
549
- this.$current.removeClass('current');
550
- $(next).addClass('current');
551
- scrollIntoView(next, this.$element[0]);
552
- this.$current = $(next);
553
- }
554
- return true;
555
- }
556
-
557
- function toggleVis($li, show) {
558
- var closed = $li.hasClass('closed'),
559
- children = $li[0].searchdoc_tree_data.children;
560
- $li.css('display', show ? '' : 'none')
561
- if (!show && this.$current && $li[0] == this.$current[0]) {
562
- this.$current.removeClass('current');
563
- this.$current = null;
564
- }
565
- for (var i=0, l = children.length; i < l; i++) {
566
- toggleVis.call(this, $(children[i].li), show && !closed);
567
- };
568
- }
569
-
570
- function buildAndAppendItem(item, level, before) {
571
- var li = renderItem(item, level),
572
- list = this.$list[0];
573
- item.li = li;
574
- list.insertBefore(li, before);
575
- for (var i=0, l = item[3].length; i < l; i++) {
576
- buildAndAppendItem.call(this, item[3][i], level + 1, before);
577
- };
578
- return li;
579
- }
580
-
581
- function renderItem(item, level) {
582
- var li = document.createElement('li'),
583
- cnt = document.createElement('div'),
584
- h1 = document.createElement('h1'),
585
- p = document.createElement('p'),
586
- icon, i;
587
-
588
- li.appendChild(cnt);
589
- li.style.paddingLeft = getOffset(level);
590
- cnt.className = 'content';
591
- if (!item[1]) li.className = 'empty ';
592
- cnt.appendChild(h1);
593
- // cnt.appendChild(p);
594
- h1.appendChild(document.createTextNode(item[0]));
595
- // p.appendChild(document.createTextNode(item[4]));
596
- if (item[2]) {
597
- i = document.createElement('i');
598
- i.appendChild(document.createTextNode(item[2]));
599
- h1.appendChild(i);
600
- }
601
- if (item[3].length > 0) {
602
- icon = document.createElement('div');
603
- icon.className = 'icon';
604
- cnt.appendChild(icon);
605
- }
606
-
607
- // user direct assignement instead of $()
608
- // it's 8x faster
609
- // $(li).data('path', item[1])
610
- // .data('children', item[3])
611
- // .data('level', level)
612
- // .css('display', level == 0 ? '' : 'none')
613
- // .addClass('level_' + level)
614
- // .addClass('closed');
615
- li.searchdoc_tree_data = {
616
- path: item[1],
617
- children: item[3],
618
- level: level
619
- }
620
- li.style.display = level == 0 ? '' : 'none';
621
- li.className += 'level_' + level + ' closed';
622
- return li;
623
- }
624
-
625
- function getOffset(level) {
626
- return 5 + 18*level + 'px';
627
- }
628
- });