pdoc 0.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.
- data/README.markdown +34 -0
- data/Rakefile +46 -0
- data/bin/pdoc +58 -0
- data/lib/pdoc.rb +32 -0
- data/lib/pdoc/error.rb +4 -0
- data/lib/pdoc/generators.rb +6 -0
- data/lib/pdoc/generators/abstract_generator.rb +16 -0
- data/lib/pdoc/generators/html.rb +8 -0
- data/lib/pdoc/generators/html/helpers.rb +256 -0
- data/lib/pdoc/generators/html/page.rb +71 -0
- data/lib/pdoc/generators/html/syntax_highlighter.rb +41 -0
- data/lib/pdoc/generators/html/template.rb +37 -0
- data/lib/pdoc/generators/html/website.rb +194 -0
- data/lib/pdoc/generators/json.rb +15 -0
- data/lib/pdoc/generators/pythonesque.rb +105 -0
- data/lib/pdoc/models.rb +47 -0
- data/lib/pdoc/models/argument.rb +37 -0
- data/lib/pdoc/models/base.rb +107 -0
- data/lib/pdoc/models/callable.rb +19 -0
- data/lib/pdoc/models/class.rb +28 -0
- data/lib/pdoc/models/class_method.rb +18 -0
- data/lib/pdoc/models/class_property.rb +9 -0
- data/lib/pdoc/models/constant.rb +9 -0
- data/lib/pdoc/models/constructor.rb +14 -0
- data/lib/pdoc/models/container.rb +114 -0
- data/lib/pdoc/models/entity.rb +54 -0
- data/lib/pdoc/models/instance_method.rb +18 -0
- data/lib/pdoc/models/instance_property.rb +9 -0
- data/lib/pdoc/models/mixin.rb +10 -0
- data/lib/pdoc/models/namespace.rb +10 -0
- data/lib/pdoc/models/root.rb +27 -0
- data/lib/pdoc/models/section.rb +19 -0
- data/lib/pdoc/models/signature.rb +27 -0
- data/lib/pdoc/models/utility.rb +11 -0
- data/lib/pdoc/parser.rb +109 -0
- data/lib/pdoc/parser/argument_description_nodes.rb +21 -0
- data/lib/pdoc/parser/basic_nodes.rb +31 -0
- data/lib/pdoc/parser/description_nodes.rb +42 -0
- data/lib/pdoc/parser/documentation_nodes.rb +483 -0
- data/lib/pdoc/parser/ebnf_arguments_nodes.rb +58 -0
- data/lib/pdoc/parser/ebnf_expression_nodes.rb +227 -0
- data/lib/pdoc/parser/fragment.rb +55 -0
- data/lib/pdoc/parser/section_content_nodes.rb +19 -0
- data/lib/pdoc/parser/tags_nodes.rb +14 -0
- data/lib/pdoc/parser/treetop_files/argument_description.treetop +31 -0
- data/lib/pdoc/parser/treetop_files/basic.treetop +41 -0
- data/lib/pdoc/parser/treetop_files/description.treetop +7 -0
- data/lib/pdoc/parser/treetop_files/documentation.treetop +75 -0
- data/lib/pdoc/parser/treetop_files/ebnf_arguments.treetop +33 -0
- data/lib/pdoc/parser/treetop_files/ebnf_expression.treetop +70 -0
- data/lib/pdoc/parser/treetop_files/ebnf_javascript.treetop +54 -0
- data/lib/pdoc/parser/treetop_files/events.treetop +17 -0
- data/lib/pdoc/parser/treetop_files/section_content.treetop +8 -0
- data/lib/pdoc/parser/treetop_files/tags.treetop +31 -0
- data/lib/pdoc/runner.rb +110 -0
- data/lib/pdoc/treemaker.rb +94 -0
- data/pdoc.gemspec +31 -0
- data/templates/html/assets/images/pdoc/alias.png +0 -0
- data/templates/html/assets/images/pdoc/class.png +0 -0
- data/templates/html/assets/images/pdoc/class_deprecated.png +0 -0
- data/templates/html/assets/images/pdoc/class_method.png +0 -0
- data/templates/html/assets/images/pdoc/class_property.png +0 -0
- data/templates/html/assets/images/pdoc/constant.png +0 -0
- data/templates/html/assets/images/pdoc/constructor.png +0 -0
- data/templates/html/assets/images/pdoc/deprecated.png +0 -0
- data/templates/html/assets/images/pdoc/description.png +0 -0
- data/templates/html/assets/images/pdoc/information.png +0 -0
- data/templates/html/assets/images/pdoc/instance_method.png +0 -0
- data/templates/html/assets/images/pdoc/instance_property.png +0 -0
- data/templates/html/assets/images/pdoc/method.png +0 -0
- data/templates/html/assets/images/pdoc/method_deprecated.png +0 -0
- data/templates/html/assets/images/pdoc/mixin.png +0 -0
- data/templates/html/assets/images/pdoc/namespace.png +0 -0
- data/templates/html/assets/images/pdoc/property.png +0 -0
- data/templates/html/assets/images/pdoc/related_to.png +0 -0
- data/templates/html/assets/images/pdoc/search-background.png +0 -0
- data/templates/html/assets/images/pdoc/section-background.png +0 -0
- data/templates/html/assets/images/pdoc/section.png +0 -0
- data/templates/html/assets/images/pdoc/selected-section-background.png +0 -0
- data/templates/html/assets/images/pdoc/subclass.png +0 -0
- data/templates/html/assets/images/pdoc/superclass.png +0 -0
- data/templates/html/assets/images/pdoc/utility.png +0 -0
- data/templates/html/assets/javascripts/pdoc/application.js +478 -0
- data/templates/html/assets/javascripts/pdoc/prototype.js +4874 -0
- data/templates/html/assets/javascripts/pdoc/tabs.js +506 -0
- data/templates/html/assets/stylesheets/pdoc/api.css +677 -0
- data/templates/html/assets/stylesheets/pdoc/pygments.css +62 -0
- data/templates/html/helpers.rb +35 -0
- data/templates/html/index.erb +18 -0
- data/templates/html/item_index.js.erb +6 -0
- data/templates/html/layout.erb +67 -0
- data/templates/html/leaf.erb +22 -0
- data/templates/html/node.erb +30 -0
- data/templates/html/partials/class_relationships.erb +19 -0
- data/templates/html/partials/classes.erb +7 -0
- data/templates/html/partials/constructor.erb +5 -0
- data/templates/html/partials/description.erb +5 -0
- data/templates/html/partials/link_list.erb +1 -0
- data/templates/html/partials/method_signatures.erb +14 -0
- data/templates/html/partials/methodized_note.erb +9 -0
- data/templates/html/partials/mixins.erb +7 -0
- data/templates/html/partials/namespaces.erb +7 -0
- data/templates/html/partials/related_utilities.erb +5 -0
- data/templates/html/partials/relationships.erb +11 -0
- data/templates/html/partials/short_description_list.erb +7 -0
- data/templates/html/partials/title.erb +22 -0
- data/templates/html/section.erb +18 -0
- data/test/unit/parser/argument_description_test.rb +40 -0
- data/test/unit/parser/basic_test.rb +55 -0
- data/test/unit/parser/description_test.rb +34 -0
- data/test/unit/parser/documentation_test.rb +520 -0
- data/test/unit/parser/ebnf_arguments_test.rb +81 -0
- data/test/unit/parser/ebnf_expression_test.rb +382 -0
- data/test/unit/parser/ebnf_javascript_test.rb +37 -0
- data/test/unit/parser/events_test.rb +27 -0
- data/test/unit/parser/section_content_test.rb +44 -0
- data/test/unit/parser/tags_test.rb +39 -0
- data/test/unit/parser/test_fragment.rb +80 -0
- data/test/unit/parser_test_helper.rb +62 -0
- data/test/unit/runner/basic_test.rb +14 -0
- data/test/unit/templates/html_helpers_test.rb +25 -0
- 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
|
+
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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
|
+
});
|