pdoc 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/README.markdown +34 -0
  2. data/Rakefile +46 -0
  3. data/bin/pdoc +58 -0
  4. data/lib/pdoc.rb +32 -0
  5. data/lib/pdoc/error.rb +4 -0
  6. data/lib/pdoc/generators.rb +6 -0
  7. data/lib/pdoc/generators/abstract_generator.rb +16 -0
  8. data/lib/pdoc/generators/html.rb +8 -0
  9. data/lib/pdoc/generators/html/helpers.rb +256 -0
  10. data/lib/pdoc/generators/html/page.rb +71 -0
  11. data/lib/pdoc/generators/html/syntax_highlighter.rb +41 -0
  12. data/lib/pdoc/generators/html/template.rb +37 -0
  13. data/lib/pdoc/generators/html/website.rb +194 -0
  14. data/lib/pdoc/generators/json.rb +15 -0
  15. data/lib/pdoc/generators/pythonesque.rb +105 -0
  16. data/lib/pdoc/models.rb +47 -0
  17. data/lib/pdoc/models/argument.rb +37 -0
  18. data/lib/pdoc/models/base.rb +107 -0
  19. data/lib/pdoc/models/callable.rb +19 -0
  20. data/lib/pdoc/models/class.rb +28 -0
  21. data/lib/pdoc/models/class_method.rb +18 -0
  22. data/lib/pdoc/models/class_property.rb +9 -0
  23. data/lib/pdoc/models/constant.rb +9 -0
  24. data/lib/pdoc/models/constructor.rb +14 -0
  25. data/lib/pdoc/models/container.rb +114 -0
  26. data/lib/pdoc/models/entity.rb +54 -0
  27. data/lib/pdoc/models/instance_method.rb +18 -0
  28. data/lib/pdoc/models/instance_property.rb +9 -0
  29. data/lib/pdoc/models/mixin.rb +10 -0
  30. data/lib/pdoc/models/namespace.rb +10 -0
  31. data/lib/pdoc/models/root.rb +27 -0
  32. data/lib/pdoc/models/section.rb +19 -0
  33. data/lib/pdoc/models/signature.rb +27 -0
  34. data/lib/pdoc/models/utility.rb +11 -0
  35. data/lib/pdoc/parser.rb +109 -0
  36. data/lib/pdoc/parser/argument_description_nodes.rb +21 -0
  37. data/lib/pdoc/parser/basic_nodes.rb +31 -0
  38. data/lib/pdoc/parser/description_nodes.rb +42 -0
  39. data/lib/pdoc/parser/documentation_nodes.rb +483 -0
  40. data/lib/pdoc/parser/ebnf_arguments_nodes.rb +58 -0
  41. data/lib/pdoc/parser/ebnf_expression_nodes.rb +227 -0
  42. data/lib/pdoc/parser/fragment.rb +55 -0
  43. data/lib/pdoc/parser/section_content_nodes.rb +19 -0
  44. data/lib/pdoc/parser/tags_nodes.rb +14 -0
  45. data/lib/pdoc/parser/treetop_files/argument_description.treetop +31 -0
  46. data/lib/pdoc/parser/treetop_files/basic.treetop +41 -0
  47. data/lib/pdoc/parser/treetop_files/description.treetop +7 -0
  48. data/lib/pdoc/parser/treetop_files/documentation.treetop +75 -0
  49. data/lib/pdoc/parser/treetop_files/ebnf_arguments.treetop +33 -0
  50. data/lib/pdoc/parser/treetop_files/ebnf_expression.treetop +70 -0
  51. data/lib/pdoc/parser/treetop_files/ebnf_javascript.treetop +54 -0
  52. data/lib/pdoc/parser/treetop_files/events.treetop +17 -0
  53. data/lib/pdoc/parser/treetop_files/section_content.treetop +8 -0
  54. data/lib/pdoc/parser/treetop_files/tags.treetop +31 -0
  55. data/lib/pdoc/runner.rb +110 -0
  56. data/lib/pdoc/treemaker.rb +94 -0
  57. data/pdoc.gemspec +31 -0
  58. data/templates/html/assets/images/pdoc/alias.png +0 -0
  59. data/templates/html/assets/images/pdoc/class.png +0 -0
  60. data/templates/html/assets/images/pdoc/class_deprecated.png +0 -0
  61. data/templates/html/assets/images/pdoc/class_method.png +0 -0
  62. data/templates/html/assets/images/pdoc/class_property.png +0 -0
  63. data/templates/html/assets/images/pdoc/constant.png +0 -0
  64. data/templates/html/assets/images/pdoc/constructor.png +0 -0
  65. data/templates/html/assets/images/pdoc/deprecated.png +0 -0
  66. data/templates/html/assets/images/pdoc/description.png +0 -0
  67. data/templates/html/assets/images/pdoc/information.png +0 -0
  68. data/templates/html/assets/images/pdoc/instance_method.png +0 -0
  69. data/templates/html/assets/images/pdoc/instance_property.png +0 -0
  70. data/templates/html/assets/images/pdoc/method.png +0 -0
  71. data/templates/html/assets/images/pdoc/method_deprecated.png +0 -0
  72. data/templates/html/assets/images/pdoc/mixin.png +0 -0
  73. data/templates/html/assets/images/pdoc/namespace.png +0 -0
  74. data/templates/html/assets/images/pdoc/property.png +0 -0
  75. data/templates/html/assets/images/pdoc/related_to.png +0 -0
  76. data/templates/html/assets/images/pdoc/search-background.png +0 -0
  77. data/templates/html/assets/images/pdoc/section-background.png +0 -0
  78. data/templates/html/assets/images/pdoc/section.png +0 -0
  79. data/templates/html/assets/images/pdoc/selected-section-background.png +0 -0
  80. data/templates/html/assets/images/pdoc/subclass.png +0 -0
  81. data/templates/html/assets/images/pdoc/superclass.png +0 -0
  82. data/templates/html/assets/images/pdoc/utility.png +0 -0
  83. data/templates/html/assets/javascripts/pdoc/application.js +478 -0
  84. data/templates/html/assets/javascripts/pdoc/prototype.js +4874 -0
  85. data/templates/html/assets/javascripts/pdoc/tabs.js +506 -0
  86. data/templates/html/assets/stylesheets/pdoc/api.css +677 -0
  87. data/templates/html/assets/stylesheets/pdoc/pygments.css +62 -0
  88. data/templates/html/helpers.rb +35 -0
  89. data/templates/html/index.erb +18 -0
  90. data/templates/html/item_index.js.erb +6 -0
  91. data/templates/html/layout.erb +67 -0
  92. data/templates/html/leaf.erb +22 -0
  93. data/templates/html/node.erb +30 -0
  94. data/templates/html/partials/class_relationships.erb +19 -0
  95. data/templates/html/partials/classes.erb +7 -0
  96. data/templates/html/partials/constructor.erb +5 -0
  97. data/templates/html/partials/description.erb +5 -0
  98. data/templates/html/partials/link_list.erb +1 -0
  99. data/templates/html/partials/method_signatures.erb +14 -0
  100. data/templates/html/partials/methodized_note.erb +9 -0
  101. data/templates/html/partials/mixins.erb +7 -0
  102. data/templates/html/partials/namespaces.erb +7 -0
  103. data/templates/html/partials/related_utilities.erb +5 -0
  104. data/templates/html/partials/relationships.erb +11 -0
  105. data/templates/html/partials/short_description_list.erb +7 -0
  106. data/templates/html/partials/title.erb +22 -0
  107. data/templates/html/section.erb +18 -0
  108. data/test/unit/parser/argument_description_test.rb +40 -0
  109. data/test/unit/parser/basic_test.rb +55 -0
  110. data/test/unit/parser/description_test.rb +34 -0
  111. data/test/unit/parser/documentation_test.rb +520 -0
  112. data/test/unit/parser/ebnf_arguments_test.rb +81 -0
  113. data/test/unit/parser/ebnf_expression_test.rb +382 -0
  114. data/test/unit/parser/ebnf_javascript_test.rb +37 -0
  115. data/test/unit/parser/events_test.rb +27 -0
  116. data/test/unit/parser/section_content_test.rb +44 -0
  117. data/test/unit/parser/tags_test.rb +39 -0
  118. data/test/unit/parser/test_fragment.rb +80 -0
  119. data/test/unit/parser_test_helper.rb +62 -0
  120. data/test/unit/runner/basic_test.rb +14 -0
  121. data/test/unit/templates/html_helpers_test.rb +25 -0
  122. metadata +222 -0
data/pdoc.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "pdoc"
3
+ s.version = "0.2.0"
4
+ s.date = "2008-11-17"
5
+ s.summary = "Inline comment parser and JavaScript documentation generator"
6
+ s.email = "tobie.langel@gmail.com"
7
+ s.homepage = "http://pdoc.org/"
8
+ s.description = "PDoc is an inline comment parser and JavaScript documentation generator written in Ruby. It is designed for documenting Prototype and Prototype-based libraries."
9
+ s.has_rdoc = true
10
+ s.authors = ["Tobie Langel"]
11
+ s.files = [
12
+ "README.markdown",
13
+ "Rakefile",
14
+ "pdoc.gemspec"] +
15
+ Dir['lib/**/*'] +
16
+ Dir['templates/**/*']
17
+
18
+ s.autorequire = "lib/pdoc.rb"
19
+
20
+ s.bindir = "bin"
21
+ s.executables = ["pdoc"]
22
+ s.default_executable = "pdoc"
23
+
24
+ s.test_files = Dir['test/**/*.rb']
25
+ s.rdoc_options = ["--main", "README.markdown"]
26
+ s.extra_rdoc_files = ["README.markdown"]
27
+ s.add_dependency("BlueCloth", ["> 0.0.0"])
28
+ s.add_dependency("treetop", ["> 0.0.0"])
29
+ s.add_dependency("oyster", ["> 0.0.0"])
30
+ end
31
+
@@ -0,0 +1,478 @@
1
+ //= require <prototype>
2
+
3
+ if (!Prototype || Prototype.Version.indexOf('1.6') !== 0) {
4
+ throw "This script requires Prototype >= 1.6.";
5
+ }
6
+
7
+ Object.isDate = function(object) {
8
+ return object instanceof Date;
9
+ };
10
+
11
+ /**
12
+ * class Cookie
13
+ * Creates a cookie.
14
+ **/
15
+ var Cookie = Class.create({
16
+ /**
17
+ * new Cookie(name, value[, expires])
18
+ *
19
+ * - name (String): The name of the cookie.
20
+ * - value (String): The value of the cookie.
21
+ * - expires (Number | Date): Exact date (or number of days from now) that
22
+ * the cookie will expire.
23
+ **/
24
+ initialize: function(name, value, expires) {
25
+ expires = expires || "";
26
+ if (Object.isNumber(expires)) {
27
+ var days = expires;
28
+ expires = new Date();
29
+ expires.setTime(expires.getTime() + (days * 24 * 60 * 60 * 1000));
30
+ }
31
+
32
+ if (Object.isDate(expires))
33
+ expires = expires.toGMTString();
34
+
35
+ if (!Object.isUndefined(expires) && expires !== "")
36
+ expires = "; expires=" + expires;
37
+
38
+ this.name = name;
39
+ this.value = value;
40
+ this.expires = expires;
41
+
42
+ document.cookie = name + "=" + value + expires + "; path=/";
43
+ },
44
+
45
+ toString: function() {
46
+ return this.value;
47
+ },
48
+
49
+ inspect: function() {
50
+ return "#<Cookie #{name}:#{value}>".interpolate(this);
51
+ }
52
+ });
53
+
54
+ /**
55
+ * Cookie
56
+ **/
57
+ Object.extend(Cookie, {
58
+ /**
59
+ * Cookie.set(name, value, expires)
60
+ *
61
+ * Alias of [[Cookie#initialize]].
62
+ **/
63
+ set: function(name, value, expires) {
64
+ return new Cookie(name, value, expires);
65
+ },
66
+
67
+ /**
68
+ * Cookie.get(name)
69
+ *
70
+ * Returns the value of the cookie with the given name.
71
+ * - name (String): The name of the cookie to retrieve.
72
+ **/
73
+ get: function(name) {
74
+ var c = document.cookie.split(';');
75
+
76
+ for (var i = 0, cookie; i < c.length; i++) {
77
+ cookie = c[i].split('=');
78
+ if (cookie[0].strip() === name)
79
+ return cookie[1].strip();
80
+ }
81
+
82
+ return null;
83
+ },
84
+
85
+ /**
86
+ * Cookie.unset(name)
87
+ *
88
+ * Deletes a cookie.
89
+ * - name (String): The name of the cookie to delete.
90
+ *
91
+ **/
92
+ unset: function(name) {
93
+ return Cookie.set(name, "", -1);
94
+ }
95
+ });
96
+
97
+ Cookie.erase = Cookie.unset;
98
+
99
+
100
+
101
+ if (typeof PDoc === 'undefined') {
102
+ window.PDoc = {
103
+ Sidebar: {}
104
+ };
105
+ }
106
+
107
+ // HISTORY MANAGER (sort of)
108
+ // Polls for changes to the hash.
109
+
110
+ (function() {
111
+ var PREVIOUS_HASH = null;
112
+
113
+ function poll() {
114
+ var hash = window.location.hash;
115
+ if (hash && hash !== PREVIOUS_HASH) {
116
+ document.fire('hash:changed', {
117
+ previous: PREVIOUS_HASH, current: hash
118
+ });
119
+ }
120
+ PREVIOUS_HASH = hash;
121
+ window.setTimeout(arguments.callee, 100);
122
+ }
123
+
124
+ Event.observe(window, 'load', poll);
125
+ })();
126
+
127
+ Object.extend(PDoc.Sidebar, {
128
+ getActiveTab: function() {
129
+ var activeTab = $('sidebar_tabs').down('.active');
130
+ if (!activeTab) return null;
131
+
132
+ var href = activeTab.readAttribute('href');
133
+ return href.endsWith('menu_pane') ? 'menu_pane' : 'search_pane';
134
+ },
135
+
136
+ // Remember the state of the sidebar so it can be restored on the next page.
137
+ serialize: function() {
138
+ var state = $H({
139
+ activeTab: PDoc.Sidebar.getActiveTab(),
140
+ menuScrollOffset: $('menu_pane').scrollTop,
141
+ searchScrollOffset: $('search_results').scrollTop,
142
+ searchValue: $('search').getValue()
143
+ });
144
+
145
+ return escape(state.toJSON());
146
+ },
147
+
148
+ // Restore the tree to a certain point based on a cookie.
149
+ restore: function(state) {
150
+ try {
151
+ state = unescape(state).evalJSON();
152
+ var filterer = $('search').retrieve('filterer');
153
+ filterer.setSearchValue(state.searchValue);
154
+
155
+ (function() {
156
+ $('menu_pane').scrollTop = state.menuScrollOffset;
157
+ $('search_results').scrollTop = state.searchScrollOffset;
158
+ }).defer();
159
+ } catch(error) {
160
+ console.log(error);
161
+ if (!(error instanceof SyntaxError)) throw error;
162
+ }
163
+ }
164
+ });
165
+
166
+
167
+
168
+ // Live API search.
169
+ PDoc.Sidebar.Filterer = Class.create({
170
+ initialize: function(element, options) {
171
+ this.element = $(element);
172
+ this.options = Object.extend(
173
+ Object.clone(PDoc.Sidebar.Filterer.DEFAULT_OPTIONS),
174
+ options || {}
175
+ );
176
+
177
+ // The browser's "helpful" auto-complete gets in the way.
178
+ this.element.writeAttribute("autocomplete", "off");
179
+ this.element.setValue('');
180
+
181
+ // Hitting "enter" should do nothing.
182
+ this.element.up('form').observe("submit", Event.stop);
183
+
184
+ this.menu = this.options.menu;
185
+ this.links = this.menu.select('a');
186
+
187
+ this.resultsElement = this.options.resultsElement;
188
+
189
+ this.observers = {
190
+ filter: this.filter.bind(this),
191
+ keydown: this.keydown.bind(this),
192
+ keyup: this.keyup.bind(this)
193
+ };
194
+
195
+ this.menu.setStyle({ opacity: 0.9 });
196
+ this.addObservers();
197
+ },
198
+
199
+ addObservers: function() {
200
+ this.element.observe('keyup', this.observers.filter);
201
+ },
202
+
203
+ // Called whenever the list of results needs to update as a result of a
204
+ // changed search key.
205
+ filter: function(event) {
206
+ // Clear the text box on ESC.
207
+ if (event.keyCode && event.keyCode === Event.KEY_ESC) {
208
+ this.element.setValue('');
209
+ }
210
+
211
+ if (PDoc.Sidebar.Filterer.INTERCEPT_KEYS.include(event.keyCode))
212
+ return;
213
+
214
+ // If there's nothing in the text box, clear the results list.
215
+ var value = $F(this.element).strip().toLowerCase();
216
+ if (value === '') {
217
+ this.emptyResults();
218
+ this.hideResults();
219
+ return;
220
+ }
221
+
222
+ var urls = this.findURLs(value);
223
+ this.buildResults(urls);
224
+ },
225
+
226
+ setSearchValue: function(value) {
227
+ this.element.setValue(value);
228
+ if (value.strip() === "") {
229
+ PDoc.Sidebar.Tabs.setActiveTab(0);
230
+ return;
231
+ }
232
+ this.buildResults(this.findURLs(value));
233
+ },
234
+
235
+ // Given a key, finds all the PDoc objects that match.
236
+ findURLs: function(str) {
237
+ var results = [];
238
+ for (var name in PDoc.elements) {
239
+ if (name.toLowerCase().include(str.toLowerCase()))
240
+ results.push(PDoc.elements[name]);
241
+ }
242
+ return results;
243
+ },
244
+
245
+ buildResults: function(results) {
246
+ this.emptyResults();
247
+
248
+ results.each( function(result) {
249
+ var li = this._buildResult(result);
250
+ this.resultsElement.appendChild(li);
251
+ }, this);
252
+ this.showResults();
253
+ },
254
+
255
+ _buildResult: function(obj) {
256
+ var li = new Element('li', { 'class': 'menu-item' });
257
+ var a = new Element('a', {
258
+ 'class': obj.type.gsub(/\s/, '-'),
259
+ 'href': PDoc.pathPrefix + obj.path
260
+ }).update(obj.name);
261
+
262
+ li.appendChild(a);
263
+ return li;
264
+ },
265
+
266
+ emptyResults: function() {
267
+ this.resultsElement.update();
268
+ },
269
+
270
+ hideResults: function() {
271
+ PDoc.Sidebar.Tabs.setActiveTab(0);
272
+ //this.resultsElement.hide();
273
+ document.stopObserving('keydown', this.observers.keydown);
274
+ document.stopObserving('keyup', this.observers.keyup);
275
+ },
276
+
277
+ showResults: function() {
278
+ PDoc.Sidebar.Tabs.setActiveTab(1);
279
+ //this.resultsElement.show();
280
+ document.stopObserving('keydown', this.observers.keydown);
281
+ this.element.stopObserving('keyup', this.observers.keyup);
282
+ this.element.observe('keydown', this.observers.keydown);
283
+ document.observe('keyup', this.observers.keyup);
284
+ },
285
+
286
+ keydown: function(event) {
287
+ if (!PDoc.Sidebar.Filterer.INTERCEPT_KEYS.include(event.keyCode))
288
+ return;
289
+
290
+ // Also ignore if any modifier keys are present.
291
+ if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey)
292
+ return;
293
+
294
+ event.stop();
295
+
296
+ if (event.keyCode === Event.KEY_RETURN) {
297
+ // Follow the highlighted item, unless there is none.
298
+ if (!this.highlighted) return;
299
+ var a = this.highlighted.down('a');
300
+ if (a) {
301
+ window.location.href = a.href;
302
+ }
303
+ } else if ([Event.KEY_UP, Event.KEY_DOWN].include(event.keyCode)) {
304
+ // Is an arrow key.
305
+ var direction = (Event.KEY_DOWN === event.keyCode) ? 1 : -1;
306
+ this.highlighted = this.moveHighlight(direction);
307
+
308
+ if (!Prototype.Browser.WebKit) {
309
+ // If up/down key is held down, list should keep scrolling.
310
+ // WebKit does this automatically because it fires the keydown
311
+ // event over and over.
312
+ this._scrollTimer = window.setTimeout(
313
+ this.scrollList.bind(this, direction), 1000);
314
+ }
315
+ }
316
+ },
317
+
318
+ keyup: function(event) {
319
+ if (this._scrollTimer) {
320
+ window.clearTimeout(this._scrollTimer);
321
+ }
322
+ },
323
+
324
+ moveHighlight: function(direction) {
325
+ if (!this.highlighted) {
326
+ // If there is none, highlight the first result.
327
+ this.highlighted =
328
+ this.resultsElement.down('li').addClassName('highlighted');
329
+ } else {
330
+ var method = (direction === 1) ? 'next' : 'previous';
331
+ this.highlighted.removeClassName('highlighted');
332
+ var adjacent = this.highlighted[method]('li');
333
+ // If there isn't an adjacent one, we're at the top or bottom
334
+ // of the list. Flip it.
335
+ if (!adjacent) {
336
+ adjacent = method == 'next' ? this.resultsElement.down('li') :
337
+ this.resultsElement.down('li:last-of-type');
338
+ }
339
+ adjacent.addClassName('highlighted');
340
+ this.highlighted = adjacent;
341
+ }
342
+
343
+ var h = this.highlighted, r = this.resultsElement;
344
+
345
+ var distanceToBottom = h.offsetTop + h.offsetHeight;
346
+ if (distanceToBottom > (r.offsetHeight + r.scrollTop)) {
347
+ // Item is below the visible frame.
348
+ r.scrollTop = distanceToBottom - r.offsetHeight;
349
+ } else if (h.offsetTop < r.scrollTop) {
350
+ // Item is above the visible frame.
351
+ r.scrollTop = h.offsetTop;
352
+ }
353
+
354
+ return this.highlighted;
355
+ },
356
+
357
+ scrollList: function(direction) {
358
+ this.moveHighlight(direction);
359
+ this._scrollTimer = window.setTimeout(
360
+ this.scrollList.bind(this, direction), 100);
361
+ }
362
+ });
363
+
364
+ Object.extend(PDoc.Sidebar.Filterer, {
365
+ INTERCEPT_KEYS: [Event.KEY_UP, Event.KEY_DOWN, Event.KEY_RETURN],
366
+ DEFAULT_OPTIONS: {
367
+ interval: 0.1,
368
+ resultsElement: '.search-results'
369
+ }
370
+ });
371
+
372
+
373
+ Form.GhostedField = Class.create({
374
+ initialize: function(element, title, options) {
375
+ options = options || {};
376
+
377
+ this.element = $(element);
378
+ this.title = title;
379
+
380
+ this.isGhosted = true;
381
+
382
+ if (options.cloak) {
383
+
384
+ // Wrap the native getValue function so that it never returns the
385
+ // ghosted value. This is optional because it presumes the ghosted
386
+ // value isn't valid input for the field.
387
+ this.element.getValue = this.element.getValue.wrap(this.wrappedGetValue.bind(this));
388
+ }
389
+
390
+ this.addObservers();
391
+
392
+ this.onBlur();
393
+ },
394
+
395
+ wrappedGetValue: function($proceed) {
396
+ var value = $proceed();
397
+ return value === this.title ? "" : value;
398
+ },
399
+
400
+ addObservers: function() {
401
+ this.element.observe('focus', this.onFocus.bind(this));
402
+ this.element.observe('blur', this.onBlur.bind(this));
403
+
404
+ var form = this.element.up('form');
405
+ if (form) {
406
+ form.observe('submit', this.onSubmit.bind(this));
407
+ }
408
+
409
+ // Firefox's bfcache means that form fields need to be re-initialized
410
+ // when you hit the "back" button to return to the page.
411
+ if (Prototype.Browser.Gecko) {
412
+ window.addEventListener('pageshow', this.onBlur.bind(this), false);
413
+ }
414
+ },
415
+
416
+ onFocus: function() {
417
+ if (this.isGhosted) {
418
+ this.element.setValue('');
419
+ this.setGhosted(false);
420
+ }
421
+ },
422
+
423
+ onBlur: function() {
424
+ var value = this.element.getValue();
425
+ if (value.blank() || value == this.title) {
426
+ this.setGhosted(true);
427
+ } else {
428
+ this.setGhosted(false);
429
+ }
430
+ },
431
+
432
+ setGhosted: function(isGhosted) {
433
+ this.isGhosted = isGhosted;
434
+ this.element[isGhosted ? 'addClassName' : 'removeClassName']('ghosted');
435
+ if (isGhosted) {
436
+ this.element.setValue(this.title);
437
+ }
438
+ },
439
+
440
+ // Hook into the enclosing form's `onsubmit` event so that we clear any
441
+ // ghosted text before the form is sent.
442
+ onSubmit: function() {
443
+ if (this.isGhosted) {
444
+ this.element.setValue('');
445
+ }
446
+ }
447
+ });
448
+
449
+ document.observe('dom:loaded', function() {
450
+ PDoc.Sidebar.Tabs = new Control.Tabs($('sidebar_tabs'));
451
+
452
+ var searchField = $('search');
453
+
454
+ if (searchField) {
455
+ var filterer = new PDoc.Sidebar.Filterer(searchField, {
456
+ menu: $('api_menu'),
457
+ resultsElement: $('search_results')
458
+ });
459
+ searchField.store('filterer', filterer);
460
+ }
461
+
462
+ // Prevent horizontal scrolling in scrollable sidebar areas.
463
+ $$('.scrollable').invoke('observe', 'scroll', function() {
464
+ this.scrollLeft = 0;
465
+ });
466
+
467
+ var sidebarState = Cookie.get('sidebar_state');
468
+ if (sidebarState) {
469
+ PDoc.Sidebar.restore(sidebarState);
470
+ }
471
+
472
+ new Form.GhostedField(searchField, searchField.getAttribute('title'),
473
+ { cloak: true });
474
+ });
475
+
476
+ Event.observe(window, 'unload', function() {
477
+ Cookie.set('sidebar_state', PDoc.Sidebar.serialize());
478
+ });