jeffreyhunter77-R2Doc 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/CHANGELOG +1 -0
  2. data/LICENSE +20 -0
  3. data/Manifest +50 -0
  4. data/R2Doc.gemspec +33 -0
  5. data/README +103 -0
  6. data/README.rdoc +103 -0
  7. data/Rakefile +9 -0
  8. data/bin/r2doc +157 -0
  9. data/lib/r2doc.rb +7 -0
  10. data/lib/r2doc/context_extensions.rb +237 -0
  11. data/lib/r2doc/erb_template_engine.rb +11 -0
  12. data/lib/r2doc/generator.rb +123 -0
  13. data/lib/r2doc/rdoc_v2_generator.rb +112 -0
  14. data/lib/r2doc/template.rb +95 -0
  15. data/lib/r2doc/template/r2doc/_aliases.html.erb +22 -0
  16. data/lib/r2doc/template/r2doc/_attributes.html.erb +24 -0
  17. data/lib/r2doc/template/r2doc/_classes_and_modules.html.erb +13 -0
  18. data/lib/r2doc/template/r2doc/_constants.html.erb +22 -0
  19. data/lib/r2doc/template/r2doc/_method_detail.html.erb +10 -0
  20. data/lib/r2doc/template/r2doc/_method_details.html.erb +17 -0
  21. data/lib/r2doc/template/r2doc/_method_listing.html.erb +37 -0
  22. data/lib/r2doc/template/r2doc/_method_listing_row.html.erb +4 -0
  23. data/lib/r2doc/template/r2doc/_nav.html.erb +40 -0
  24. data/lib/r2doc/template/r2doc/_nav_item.html.erb +1 -0
  25. data/lib/r2doc/template/r2doc/class.html.erb +71 -0
  26. data/lib/r2doc/template/r2doc/file.html.erb +52 -0
  27. data/lib/r2doc/template/r2doc/images/blue-arrow-right.png +0 -0
  28. data/lib/r2doc/template/r2doc/images/blue-arrow-up.png +0 -0
  29. data/lib/r2doc/template/r2doc/images/blue-box.png +0 -0
  30. data/lib/r2doc/template/r2doc/images/blue-plus.png +0 -0
  31. data/lib/r2doc/template/r2doc/images/close-button.png +0 -0
  32. data/lib/r2doc/template/r2doc/images/green-arrow-right.png +0 -0
  33. data/lib/r2doc/template/r2doc/images/green-arrow-up.png +0 -0
  34. data/lib/r2doc/template/r2doc/images/nav-back.png +0 -0
  35. data/lib/r2doc/template/r2doc/images/nav-bottom.png +0 -0
  36. data/lib/r2doc/template/r2doc/images/nav-top.png +0 -0
  37. data/lib/r2doc/template/r2doc/images/orange-hash.png +0 -0
  38. data/lib/r2doc/template/r2doc/images/red-dash.png +0 -0
  39. data/lib/r2doc/template/r2doc/images/search-back.png +0 -0
  40. data/lib/r2doc/template/r2doc/images/top-back.png +0 -0
  41. data/lib/r2doc/template/r2doc/images/top-left.png +0 -0
  42. data/lib/r2doc/template/r2doc/images/top-right.png +0 -0
  43. data/lib/r2doc/template/r2doc/index.html.erb +42 -0
  44. data/lib/r2doc/template/r2doc/jquery.js +19 -0
  45. data/lib/r2doc/template/r2doc/prototype.js +285 -0
  46. data/lib/r2doc/template/r2doc/r2doc.css +400 -0
  47. data/lib/r2doc/template/r2doc/rdoc-utils.js +510 -0
  48. data/lib/r2doc/template/r2doc/rdoc.js.erb +164 -0
  49. data/lib/r2doc/template_util.rb +82 -0
  50. data/lib/rdoc/discover.rb +4 -0
  51. data/lib/rdoc/generators/r2doc_generator.rb +105 -0
  52. metadata +155 -0
@@ -0,0 +1,510 @@
1
+ /* R2Doc
2
+ * Copyright (c) 2009 Jeffrey Hunter and Mission Critical Labs, Inc.
3
+ *
4
+ * Distributable under an MIT-style license. See LICENSE file for details.
5
+ */
6
+
7
+
8
+ /**
9
+ * 'Namespace' for rdoc-related stuff
10
+ */
11
+ var rdoc = {};
12
+
13
+ /**
14
+ * Utility function for generating the URL from one page to another.
15
+ */
16
+ rdoc.genUrl = function(fromUrl, toUrl) {
17
+ var fromItems = fromUrl.split(/\\+|\/+/);
18
+ var toItems = toUrl.split(/\\+|\/+/);
19
+
20
+ fromItems.pop();
21
+ var toFile = toItems.pop();
22
+
23
+ while (fromItems.length > 0 && toItems.length > 0 && fromItems[0] == toItems[0]) {
24
+ fromItems.shift();
25
+ toItems.shift();
26
+ }
27
+
28
+ var url = [];
29
+ for (var i = 0; i < fromItems.length; i++) { url.push('..'); }
30
+
31
+ url = url.concat(toItems);
32
+ url.push(toFile);
33
+ return url.join('/');
34
+ }
35
+
36
+ /**
37
+ * Base class for custom autocompleters.
38
+ *
39
+ * This class is an abstract class intended for creating your own
40
+ * autocompletion widget. Derived classes must define the methods
41
+ * delayedUpdate(), determineIds(), setIds(result). The methods are
42
+ * described in greater detail below. This class does not provide an
43
+ * initialize method of its own. It defines a method named
44
+ * baseInitialize which is intended to be called from the derived class's
45
+ * initialize function.
46
+ *
47
+ * The delayedUpdate() method is responsible for retrieving the list of
48
+ * possible autocompletion options. It typically passes this back by
49
+ * calling newSelections(). newSelections() expects an array of objects
50
+ * representing each possible selection. At a minimum, each object must
51
+ * provide two properties: display_name and description. Note that
52
+ * display_name is the value that will be evaluated to see if it matches
53
+ * what the user has typed.
54
+ *
55
+ * The determineIds() method is called when the control loses focus
56
+ * without a selection being chosen through any of the autocompletion
57
+ * means (e.g. by clicking an item, hitting tab, or hitting return).
58
+ * This is an opportunity for the control to perform any cleanup needed
59
+ * for a typed in response (for example, lookup an id based on the typed
60
+ * in text).
61
+ *
62
+ * The setIds() method is called when a specific item from the list of
63
+ * autocompletion options is chosen. The item chose is passed to the
64
+ * funtion. If the delayedUpdate() method passes a list of objects to
65
+ * newSelections(), the object passed to setIds() will be the selected
66
+ * object from the list.
67
+ */
68
+ rdoc.CustomAutoCompleter = Class.create();
69
+ rdoc.CustomAutoCompleter.prototype = {
70
+ /**
71
+ * Constructor
72
+ *
73
+ * @param elem The element or id to preform autocompletion for
74
+ * @param chooser The element or id of the window that diplays the choices
75
+ */
76
+ baseInitialize: function(elem, chooser) {
77
+ this.element = $(elem);
78
+ this.chooser = $(chooser);
79
+ this.visible = false;
80
+ this.selectedIndex = null;
81
+ this.selectedElem = null;
82
+ this.options = null;
83
+ this.selectionSet = false;
84
+ this.listClickCallback = this.onListClick.bind(this);
85
+ this.updateTimer = null;
86
+
87
+ // prep the chooser
88
+ this.chooser.style.display = 'none';
89
+
90
+ // prep the element
91
+ this.element.setAttribute('autocomplete','off');
92
+ Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
93
+ Event.observe(this.element, "keydown", this.onKeyPress.bindAsEventListener(this));
94
+ },
95
+
96
+ /**
97
+ * Called when a key is pressed for the autocompleting element
98
+ */
99
+ onKeyPress: function(event) {
100
+ switch(event.keyCode) {
101
+ case Event.KEY_TAB:
102
+ case Event.KEY_RETURN:
103
+ if (this.selectedIndex != null) {
104
+ this.useSelection();
105
+ Event.stop(event);
106
+ }
107
+ return;
108
+
109
+ case Event.KEY_ESC:
110
+ this.hide();
111
+ Event.stop(event);
112
+ return;
113
+
114
+ case Event.KEY_LEFT:
115
+ case Event.KEY_RIGHT:
116
+ return;
117
+
118
+ case Event.KEY_UP:
119
+ this.selectionSet = false;
120
+ this.selectionUp();
121
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
122
+ return;
123
+
124
+ case Event.KEY_DOWN:
125
+ if (!this.visible) {
126
+ this.updateSelectionsNow();
127
+ } else {
128
+ this.selectionSet = false;
129
+ this.selectionDown();
130
+ }
131
+ if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
132
+ return;
133
+ }
134
+
135
+ this.selectionSet = false;
136
+ this.updateSelections();
137
+ },
138
+
139
+ /**
140
+ * Called when the autocompleting element loses focus
141
+ */
142
+ onBlur: function(event) {
143
+ // to make sure click events work on the list
144
+ setTimeout(this.afterBlur.bind(this), 250);
145
+ },
146
+
147
+ /**
148
+ * Called after focus has already been lost
149
+ */
150
+ afterBlur: function() {
151
+ if (!this.selectionSet) this.determineIds();
152
+ this.hide();
153
+ },
154
+
155
+ /**
156
+ * Makes the selected item the new element value
157
+ */
158
+ useSelection: function() {
159
+ if (this.selectedIndex == null) return;
160
+
161
+ var selected = this.options[this.selectedIndex];
162
+ this.setIds(selected);
163
+ this.hide();
164
+ },
165
+
166
+ /**
167
+ * Turn off the selection window
168
+ */
169
+ hide: function() {
170
+ this.visible = false;
171
+ this.selectedIndex = null;
172
+ this.selectedElem = null;
173
+ this.chooser.style.display = 'none';
174
+ },
175
+
176
+ /**
177
+ * Move the selection up one item in the list
178
+ */
179
+ selectionUp: function() {
180
+ if (!this.selectedElem) return;
181
+ if (!this.selectedElem.previousSibling) return;
182
+
183
+ this.selectedElem.className = '';
184
+ this.selectedElem = this.selectedElem.previousSibling;
185
+ this.selectedIndex = this.selectedElem.optionIndex;
186
+ this.selectedElem.className = 'selected';
187
+ this.scrollIntoView(this.selectedElem);
188
+ },
189
+
190
+ /**
191
+ * Move the selection down one item in the list
192
+ */
193
+ selectionDown: function() {
194
+ if (!this.selectedElem) {
195
+ this.selectFirst();
196
+ return;
197
+ }
198
+
199
+ if (!this.selectedElem.nextSibling) return;
200
+
201
+ this.selectedElem.className = '';
202
+ this.selectedElem = this.selectedElem.nextSibling;
203
+ this.selectedIndex = this.selectedElem.optionIndex;
204
+ this.selectedElem.className = 'selected';
205
+ this.scrollIntoView(this.selectedElem);
206
+ },
207
+
208
+ /**
209
+ * Select the first element
210
+ */
211
+ selectFirst: function() {
212
+ if (this.options.length > 0) {
213
+ this.selectedIndex = 0;
214
+ this.selectedElem = this.chooser.down('li');
215
+ if (this.selectedElem) {
216
+ this.selectedElem.className = 'selected';
217
+ this.scrollIntoView(this.selectedElem);
218
+ return true;
219
+ } else {
220
+ return false;
221
+ }
222
+ }
223
+
224
+ return false;
225
+ },
226
+
227
+ /**
228
+ * Scroll the list of selections, if necessary, so that the given item is
229
+ * visible
230
+ */
231
+ scrollIntoView: function(elem) {
232
+ var topY = elem.offsetTop - this.chooser.scrollTop;
233
+ var bottomY = topY + elem.offsetHeight;
234
+
235
+ // if the top is too high, scroll down
236
+ if (topY < 0) {
237
+ this.chooser.scrollTop = elem.offsetTop;
238
+ // otherwise, if the bottom is too low, scroll up
239
+ } else if (bottomY > this.chooser.clientHeight) {
240
+ this.chooser.scrollTop = elem.offsetTop - this.chooser.clientHeight + elem.offsetHeight;
241
+ }
242
+ },
243
+
244
+ /**
245
+ * Click event handler for list items
246
+ */
247
+ onListClick: function(event) {
248
+ var li = Event.findElement(event, 'LI');
249
+ if (!li) return;
250
+
251
+ if (this.selectedElem) this.selectedElem.className = '';
252
+
253
+ this.selectedElem = li;
254
+ this.selectedIndex = li.optionIndex;
255
+ li.className = 'selected';
256
+ this.useSelection();
257
+ },
258
+
259
+ /**
260
+ * Update the list of selections
261
+ */
262
+ updateSelections: function() {
263
+ this.visible = true;
264
+ if (this.updateTimer != null) clearTimeout(this.updateTimer);
265
+ this.updateTimer = setTimeout(this.delayedUpdate.bind(this), 250);
266
+ },
267
+
268
+ /**
269
+ * Perform an immediate update the list of selections
270
+ */
271
+ updateSelectionsNow: function() {
272
+ this.visible = true;
273
+ if (this.updateTimer != null) clearTimeout(this.updateTimer);
274
+ this.updateTimer = setTimeout(this.delayedUpdate.bind(this), 1);
275
+ },
276
+
277
+ /**
278
+ * Called when new selections are retrieved
279
+ */
280
+ newSelections: function(allOptions, preserveSelectedIndex) {
281
+ if (!this.visible) return;
282
+
283
+ var txt = this.element.value.toUpperCase();
284
+
285
+ // examine all possibilities and show only those beginning with the currently entered text
286
+ this.options = [];
287
+ var i;
288
+ for (i = 0; i < allOptions.length; i++) {
289
+ if (allOptions[i].display_name.substring(0, txt.length).toUpperCase() == txt)
290
+ this.options.push(allOptions[i]);
291
+ }
292
+
293
+ if (!preserveSelectedIndex)
294
+ this.selectedIndex = 0;
295
+ this.updateDisplay();
296
+ },
297
+
298
+ /**
299
+ * Update the selection box with a new set of options
300
+ */
301
+ updateDisplay: function() {
302
+ // just hide the display if nothing matches
303
+ if (this.options.length == 0) {
304
+ this.hide();
305
+ return;
306
+ }
307
+
308
+ // create the list
309
+ var ul = document.createElement('UL');
310
+ var idx = 0;
311
+
312
+ while (idx < this.options.length) {
313
+ var li = document.createElement('LI');
314
+ li.innerHTML = this.options[idx].display_name.escapeHTML() + ' <span class="description">' + this.options[idx].description.escapeHTML() + '</span>';
315
+ li.optionIndex = idx;
316
+ Event.observe(li, 'click', this.listClickCallback);
317
+ if (this.selectedIndex == idx) {
318
+ li.className = 'selected';
319
+ this.selectedElem = li;
320
+ }
321
+ ul.appendChild(li);
322
+ idx++;
323
+ }
324
+
325
+ // populate the display
326
+ while (this.chooser.hasChildNodes()) { this.chooser.removeChild(this.chooser.childNodes[0]); }
327
+ this.chooser.appendChild(ul);
328
+
329
+ if (this.chooser.style.display != 'block') {
330
+ this.chooser.style.zIndex = 1;
331
+ this.chooser.style.position = 'absolute';
332
+ this.positionChooser();
333
+ this.displayChooser();
334
+ }
335
+ },
336
+
337
+ /**
338
+ * Set the position for the chooser window
339
+ */
340
+ positionChooser: function() {
341
+ Position.clone(this.element, this.chooser, {setHeight: false, offsetTop: this.element.offsetHeight});
342
+ },
343
+
344
+ /**
345
+ * Effect for displaying the chooser. Can be overridden.
346
+ */
347
+ displayChooser: function() {
348
+ jQuery(this.chooser).slideDown('fast');
349
+ }
350
+ };
351
+
352
+ /**
353
+ * Base class for custom modal dialogs
354
+ *
355
+ * Supported options:
356
+ * maskOpacity - Opacity (0.0 to 1.0) of the background behind the dialog
357
+ * maskColor - Color of the background behind the dialog
358
+ * maskZIndex - Z-index of the background behind the dialog
359
+ * container - Id or element to contain the dialog (defaults to body element)
360
+ */
361
+ rdoc.CustomDialog = Class.create();
362
+ rdoc.CustomDialog.prototype = {
363
+ /**
364
+ * Constructor
365
+ */
366
+ baseInitialize: function(options) {
367
+ this.options = {maskOpacity: 0.6, maskColor: '#000', maskZIndex: 1000};
368
+ if (options) this.options = Object.extend(this.options, options);
369
+
370
+ this.background = this.initBack();
371
+ this.dialog = this.initDialog();
372
+ },
373
+
374
+ /**
375
+ * Display the dialog
376
+ */
377
+ open: function(id) {
378
+ var size = this.pageDimensions();
379
+
380
+ this.background.style.top = '0px';
381
+ this.background.style.left = '0px';
382
+ this.background.style.width = size.width + 'px';
383
+ this.background.style.height = size.height + 'px';
384
+ if (this.options.maskOpacity) this.background.setOpacity(this.options.maskOpacity);
385
+ jQuery(this.background).fadeIn('normal');
386
+
387
+ this.centerDialog(size);
388
+ jQuery(this.dialog).fadeIn('normal');
389
+ },
390
+
391
+ /**
392
+ * Close/hide the dialog
393
+ */
394
+ close: function() {
395
+ jQuery(this.background).fadeOut();
396
+ jQuery(this.dialog).fadeOut();
397
+ },
398
+
399
+ /**
400
+ * Center the dialog
401
+ */
402
+ centerDialog: function(size) {
403
+ var scrollY = (window.scrollY ? window.scrollY : (document.body.scrollY ? document.body.scrollY : (document.documentElement.scrollTop ? document.documentElement.scrollTop : 0)));
404
+
405
+ this.dialog.style.top = (scrollY + 40) + 'px';
406
+ this.dialog.style.left = Math.floor((size.width - this.dialogWidth()) / 2) + 'px';
407
+ },
408
+
409
+ /**
410
+ * Return the width of the dialog in pixels
411
+ */
412
+ dialogWidth: function() {
413
+ return this.dialog.clientWidth;
414
+ },
415
+
416
+ /**
417
+ * Create the background element
418
+ */
419
+ initBack: function() {
420
+ var div = document.createElement('div');
421
+ div.style.position = 'absolute';
422
+ div.style.display = 'none';
423
+ if (this.options.maskColor) div.style.backgroundColor = this.options.maskColor;
424
+ if (this.options.maskZIndex) div.style.zIndex = this.options.maskZIndex;
425
+ var container = this.options.container ? $(this.options.container) : $$('body').first();
426
+ container.appendChild(div);
427
+ return $(div);
428
+ },
429
+
430
+ /**
431
+ * Create the dialog element
432
+ */
433
+ initDialog: function() {
434
+ var div = document.createElement('div');
435
+ div.style.position = 'absolute';
436
+ div.style.display = 'none';
437
+ if (this.options.maskZIndex) div.style.zIndex = this.options.maskZIndex + 1;
438
+ var container = this.options.container ? $(this.options.container) : $$('body').first();
439
+ container.appendChild(div);
440
+ return $(div);
441
+ },
442
+
443
+ /**
444
+ * Current scrollable size
445
+ */
446
+ scrollableDimensions: function() {
447
+ var size = {};
448
+
449
+ if (window.innerHeight && window.scrollMaxY) {
450
+ var baseWidth = document.documentElement.clientWidth ? document.documentElement.clientWidth : window.innerWidth;
451
+ size.width = baseWidth + window.scrollMaxX;
452
+ size.height = window.innerHeight + window.scrollMaxY;
453
+ } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
454
+ size.width = document.body.scrollWidth;
455
+ size.height = document.body.scrollHeight;
456
+ } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
457
+ size.width = document.body.offsetWidth;
458
+ if (document.documentElement && document.documentElement.scrollHeight > document.body.offsetHeight)
459
+ size.height = document.documentElement.scrollHeight;
460
+ else
461
+ size.height = document.body.offsetHeight;
462
+ }
463
+
464
+ return size;
465
+ },
466
+
467
+ /**
468
+ * Current document size
469
+ */
470
+ documentDimensions: function() {
471
+ var size = {};
472
+
473
+ if (self.innerHeight) { // all except Explorer
474
+ size.width = document.documentElement.clientWidth ?
475
+ document.documentElement.clientWidth : self.innerWidth;
476
+ size.height = self.innerHeight;
477
+ } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
478
+ if (document.body && document.body.clientWidth > document.documentElement.clientWidth)
479
+ size.width = document.body.clientWidth;
480
+ else
481
+ size.width = document.documentElement.clientWidth;
482
+ if (document.body && document.body.clientHeight > document.documentElement.clientHeight)
483
+ size.height = document.body.clientHeight;
484
+ else
485
+ size.height = document.documentElement.clientHeight;
486
+ } else if (document.body) { // other Explorers
487
+ size.width = document.body.clientWidth;
488
+ size.height = document.body.clientHeight;
489
+ }
490
+
491
+ return size;
492
+ },
493
+
494
+ /**
495
+ * Determine the current page size
496
+ */
497
+ pageDimensions: function () {
498
+ var scrollSize = this.scrollableDimensions();
499
+ var winSize = this.documentDimensions();
500
+ var pageSize = {};
501
+
502
+ // for small pages with total height less then height of the viewport
503
+ pageSize.height = (scrollSize.height < winSize.height) ? winSize.height : scrollSize.height;
504
+ // for small pages with total width less then width of the viewport
505
+ pageSize.width = (scrollSize.width < winSize.width) ? winSize.width : scrollSize.width;
506
+
507
+ return pageSize;
508
+ }
509
+
510
+ };