jsduck 0.4 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +29 -13
- data/Rakefile +5 -5
- data/bin/jsduck +26 -2
- data/jsduck.gemspec +2 -2
- data/lib/jsduck/app.rb +68 -19
- data/lib/jsduck/class.rb +31 -4
- data/lib/jsduck/doc_formatter.rb +61 -10
- data/lib/jsduck/doc_parser.rb +1 -1
- data/lib/jsduck/exporter.rb +75 -0
- data/lib/jsduck/inheritance_tree.rb +8 -12
- data/lib/jsduck/lexer.rb +2 -2
- data/lib/jsduck/long_params.rb +4 -1
- data/lib/jsduck/members.rb +57 -0
- data/lib/jsduck/merger.rb +4 -1
- data/lib/jsduck/method_table.rb +5 -1
- data/lib/jsduck/page.rb +34 -18
- data/lib/jsduck/parallel_wrap.rb +31 -0
- data/lib/jsduck/relations.rb +68 -0
- data/lib/jsduck/short_params.rb +1 -5
- data/lib/jsduck/source_formatter.rb +9 -4
- data/lib/jsduck/table.rb +9 -27
- data/template/index.html +1 -0
- data/template/resources/docs.css +3 -1
- data/template/resources/docs.js +49 -35
- metadata +8 -5
- data/lib/jsduck/subclasses.rb +0 -27
data/README.md
CHANGED
@@ -117,26 +117,35 @@ JsDuck depends on [json][], [RDiscount][], and [parallel][] plus [RSpec][] for t
|
|
117
117
|
Usage
|
118
118
|
-----
|
119
119
|
|
120
|
-
Just call it from command line with output directory and a
|
121
|
-
JavaScript files:
|
120
|
+
Just call it from command line with output directory and a directory
|
121
|
+
containing your JavaScript files:
|
122
122
|
|
123
|
-
$ jsduck --verbose --output some/dir your/project
|
123
|
+
$ jsduck --verbose --output some/dir your/project/js
|
124
124
|
|
125
|
-
|
126
|
-
|
125
|
+
The `--verbose` flag creates a lot of output, but at least you will
|
126
|
+
see that something is happening.
|
127
127
|
|
128
|
-
|
128
|
+
You pass in both directories and JavaScript files. For example to
|
129
|
+
generate docs for ExtJS 3, the simplest way is the following:
|
129
130
|
|
130
|
-
$
|
131
|
+
$ jsduck -v -o output/ ext-3.3.1/src/
|
131
132
|
|
132
|
-
|
133
|
-
|
133
|
+
But this will give you a bunch of warnings, so you should better
|
134
|
+
create a script that takes just the files really needed and passes
|
135
|
+
them through `xargs` to `jsduck`:
|
134
136
|
|
135
|
-
|
137
|
+
$ find ext-3.3.1/src/ -name '*.js' | egrep -v 'locale/|test/|adapter/' | xargs jsduck -v -o output/
|
138
|
+
|
139
|
+
Here's how the resulting documentation will look (ExtJS 3.3.1):
|
136
140
|
|
137
141
|
* [JsDuck generated documentation](http://triin.net/temp/jsduck/)
|
138
142
|
* [Official ExtJS documentation](http://dev.sencha.com/deploy/dev/docs/) (for comparison)
|
139
143
|
|
144
|
+
Here's the same for ExtJS 4 Preview 5:
|
145
|
+
|
146
|
+
* [JsDuck generated documentation](http://triin.net/temp/jsduck4/)
|
147
|
+
* [Official ExtJS documentation](http://dev.sencha.com/deploy/ext-4.0-pr5/docs/) (for comparison)
|
148
|
+
|
140
149
|
|
141
150
|
Documentation
|
142
151
|
-------------
|
@@ -178,8 +187,6 @@ missing.
|
|
178
187
|
Missing features and TODO
|
179
188
|
-------------------------
|
180
189
|
|
181
|
-
* Search, not just searching from official ExtJS documentation.
|
182
|
-
|
183
190
|
* Support for custom @tags. Ext-doc supports this, I personally have
|
184
191
|
never used this feature, so I'm thinking it's not really needed.
|
185
192
|
|
@@ -189,12 +196,21 @@ Copying
|
|
189
196
|
|
190
197
|
JsDuck is distributed under the terms of the GNU General Public License version 3.
|
191
198
|
|
192
|
-
JsDuck was developed by [Rene Saarsoo](http://triin.net)
|
199
|
+
JsDuck was developed by [Rene Saarsoo](http://triin.net),
|
200
|
+
with contributions from [Ondřej Jirman](https://github.com/megous).
|
193
201
|
|
194
202
|
|
195
203
|
Changelog
|
196
204
|
---------
|
197
205
|
|
206
|
+
* 0.5 - Search and export
|
207
|
+
* Search from the actually generated docs (not through sencha.com)
|
208
|
+
* JSON export with --json switch.
|
209
|
+
* Listing of mixed into classes.
|
210
|
+
* Option to control or disable parallel processing.
|
211
|
+
* Accepting directories as input (those are scanned for .js files)
|
212
|
+
* Many bug fixes.
|
213
|
+
|
198
214
|
* 0.4 - Ext4 support
|
199
215
|
* Support for Ext.define() syntax from ExtJS 4.
|
200
216
|
* Showing @xtype and @author information on generated pages.
|
data/Rakefile
CHANGED
@@ -3,11 +3,11 @@ require 'rake'
|
|
3
3
|
|
4
4
|
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
5
5
|
|
6
|
-
require '
|
7
|
-
require '
|
8
|
-
|
9
|
-
spec.
|
10
|
-
spec.
|
6
|
+
require 'rspec'
|
7
|
+
require 'rspec/core/rake_task'
|
8
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
9
|
+
spec.rspec_opts = ["--color"]
|
10
|
+
spec.pattern = "spec/**/*_spec.rb"
|
11
11
|
end
|
12
12
|
|
13
13
|
desc "Build gem locally"
|
data/bin/jsduck
CHANGED
@@ -24,7 +24,7 @@ app = JsDuck::App.new
|
|
24
24
|
app.template_dir = File.dirname(File.dirname(__FILE__)) + "/template"
|
25
25
|
|
26
26
|
opts = OptionParser.new do | opts |
|
27
|
-
opts.banner = "Usage: jsduck [options] files..."
|
27
|
+
opts.banner = "Usage: jsduck [options] files/dirs..."
|
28
28
|
|
29
29
|
opts.on('-o', '--output=PATH', "Directory to output all this amazing documentation.") do |path|
|
30
30
|
app.output_dir = path
|
@@ -34,6 +34,17 @@ opts = OptionParser.new do | opts |
|
|
34
34
|
app.template_dir = path
|
35
35
|
end
|
36
36
|
|
37
|
+
opts.on('--json', "Produces JSON export instead of HTML documentation.") do |path|
|
38
|
+
app.export = :json
|
39
|
+
end
|
40
|
+
|
41
|
+
# For debugging it's often useful to set --processes=0 to get deterministic results.
|
42
|
+
opts.on('-p', '--processes=COUNT', "The number of parallel processes to use.",
|
43
|
+
"Defaults to the number of processors/cores.",
|
44
|
+
"Set to 0 to disable parallel processing completely.") do |count|
|
45
|
+
app.processes = count.to_i
|
46
|
+
end
|
47
|
+
|
37
48
|
opts.on('-v', '--verbose', "This will fill up your console.") do
|
38
49
|
app.verbose = true
|
39
50
|
end
|
@@ -44,7 +55,20 @@ opts = OptionParser.new do | opts |
|
|
44
55
|
end
|
45
56
|
end
|
46
57
|
|
47
|
-
|
58
|
+
js_files = []
|
59
|
+
# scan directories for .js files
|
60
|
+
opts.parse!(ARGV).each do |fname|
|
61
|
+
if File.exists?(fname)
|
62
|
+
if File.directory?(fname)
|
63
|
+
Dir[fname+"/**/*.js"].each {|f| js_files << f }
|
64
|
+
else
|
65
|
+
js_files << fname
|
66
|
+
end
|
67
|
+
else
|
68
|
+
puts "Warning: File #{fname} not found"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
app.input_files = js_files
|
48
72
|
|
49
73
|
if app.input_files.length == 0
|
50
74
|
puts "You should specify some input files, otherwise there's nothing I can do :("
|
data/jsduck.gemspec
CHANGED
@@ -2,8 +2,8 @@ Gem::Specification.new do |s|
|
|
2
2
|
s.required_rubygems_version = ">= 1.3.7"
|
3
3
|
|
4
4
|
s.name = 'jsduck'
|
5
|
-
s.version = '0.
|
6
|
-
s.date = '2011-
|
5
|
+
s.version = '0.5'
|
6
|
+
s.date = '2011-03-29'
|
7
7
|
s.summary = "Simple JavaScript Duckumentation generator"
|
8
8
|
s.description = "Better ext-doc like JavaScript documentation generator for ExtJS"
|
9
9
|
s.homepage = "https://github.com/nene/jsduck"
|
data/lib/jsduck/app.rb
CHANGED
@@ -5,12 +5,14 @@ require 'jsduck/source_formatter'
|
|
5
5
|
require 'jsduck/class'
|
6
6
|
require 'jsduck/tree'
|
7
7
|
require 'jsduck/tree_icons'
|
8
|
-
require 'jsduck/
|
8
|
+
require 'jsduck/members'
|
9
|
+
require 'jsduck/relations'
|
9
10
|
require 'jsduck/page'
|
11
|
+
require 'jsduck/exporter'
|
10
12
|
require 'jsduck/timer'
|
13
|
+
require 'jsduck/parallel_wrap'
|
11
14
|
require 'json'
|
12
15
|
require 'fileutils'
|
13
|
-
require 'parallel'
|
14
16
|
|
15
17
|
module JsDuck
|
16
18
|
|
@@ -21,32 +23,53 @@ module JsDuck
|
|
21
23
|
attr_accessor :template_dir
|
22
24
|
attr_accessor :input_files
|
23
25
|
attr_accessor :verbose
|
26
|
+
attr_accessor :export
|
24
27
|
|
25
28
|
def initialize
|
26
29
|
@output_dir = nil
|
27
30
|
@template_dir = nil
|
28
31
|
@input_files = []
|
29
32
|
@verbose = false
|
33
|
+
@export = nil
|
30
34
|
@timer = Timer.new
|
35
|
+
@parallel = ParallelWrap.new
|
36
|
+
end
|
37
|
+
|
38
|
+
# Sets the nr of parallel processes to use.
|
39
|
+
# Set to 0 to disable parallelization completely.
|
40
|
+
def processes=(count)
|
41
|
+
@parallel = ParallelWrap.new(:in_processes => count)
|
31
42
|
end
|
32
43
|
|
33
44
|
# Call this after input parameters set
|
34
45
|
def run
|
35
|
-
|
46
|
+
clear_dir(@output_dir)
|
47
|
+
if @export
|
48
|
+
FileUtils.mkdir(@output_dir)
|
49
|
+
init_output_dirs(@output_dir)
|
50
|
+
else
|
51
|
+
copy_template(@template_dir, @output_dir)
|
52
|
+
end
|
36
53
|
|
37
54
|
parsed_files = @timer.time(:parsing) { parallel_parse(@input_files) }
|
38
55
|
result = @timer.time(:aggregating) { aggregate(parsed_files) }
|
39
|
-
|
40
|
-
|
41
|
-
|
56
|
+
relations = @timer.time(:aggregating) { filter_classes(result) }
|
57
|
+
|
58
|
+
if @export == :json
|
59
|
+
@timer.time(:generating) { write_json(@output_dir+"/output", relations) }
|
60
|
+
else
|
61
|
+
@timer.time(:generating) { write_tree(@output_dir+"/output/tree.js", relations) }
|
62
|
+
@timer.time(:generating) { write_members(@output_dir+"/output/members.js", relations) }
|
63
|
+
@timer.time(:generating) { write_pages(@output_dir+"/output", relations) }
|
64
|
+
end
|
42
65
|
|
43
66
|
@timer.report if @verbose
|
44
67
|
end
|
45
68
|
|
46
69
|
# Parses the files in parallel using as many processes as available CPU-s
|
47
70
|
def parallel_parse(filenames)
|
48
|
-
src = SourceFormatter.new(@output_dir + "/source")
|
49
|
-
|
71
|
+
src = SourceFormatter.new(@output_dir + "/source", @export ? :format_pre : :format_page)
|
72
|
+
@parallel.map(filenames) do |fname|
|
50
73
|
puts "Parsing #{fname} ..." if @verbose
|
51
74
|
code = IO.read(fname)
|
52
75
|
{
|
@@ -70,10 +93,10 @@ module JsDuck
|
|
70
93
|
# Filters out class-documentations, converting them to Class objects.
|
71
94
|
# For each other type, prints a warning message and discards it
|
72
95
|
def filter_classes(docs)
|
73
|
-
classes =
|
96
|
+
classes = []
|
74
97
|
docs.each do |d|
|
75
98
|
if d[:tagname] == :class
|
76
|
-
classes
|
99
|
+
classes << Class.new(d)
|
77
100
|
else
|
78
101
|
type = d[:tagname].to_s
|
79
102
|
name = d[:name]
|
@@ -82,38 +105,64 @@ module JsDuck
|
|
82
105
|
puts "Warning: Ignoring #{type}: #{name} in #{file} line #{line}"
|
83
106
|
end
|
84
107
|
end
|
85
|
-
classes
|
108
|
+
Relations.new(classes)
|
86
109
|
end
|
87
110
|
|
88
|
-
# Given
|
111
|
+
# Given all classes, generates namespace tree and writes it
|
89
112
|
# in JSON form into a file.
|
90
|
-
def write_tree(filename,
|
91
|
-
tree = Tree.new.create(
|
113
|
+
def write_tree(filename, relations)
|
114
|
+
tree = Tree.new.create(relations.classes)
|
92
115
|
icons = TreeIcons.new.extract_icons(tree)
|
93
116
|
js = "Docs.classData = " + JSON.generate( tree ) + ";"
|
94
117
|
js += "Docs.icons = " + JSON.generate( icons ) + ";"
|
95
118
|
File.open(filename, 'w') {|f| f.write(js) }
|
96
119
|
end
|
97
120
|
|
121
|
+
# Given all classes, generates members data for search and writes in
|
122
|
+
# in JSON form into a file.
|
123
|
+
def write_members(filename, relations)
|
124
|
+
members = Members.new.create(relations.classes)
|
125
|
+
js = "Docs.membersData = " + JSON.generate( {:data => members} ) + ";"
|
126
|
+
File.open(filename, 'w') {|f| f.write(js) }
|
127
|
+
end
|
128
|
+
|
98
129
|
# Writes documentation page for each class
|
99
130
|
# We do it in parallel using as many processes as available CPU-s
|
100
|
-
def write_pages(path,
|
101
|
-
subclasses = Subclasses.new(docs)
|
131
|
+
def write_pages(path, relations)
|
102
132
|
cache = {}
|
103
|
-
|
133
|
+
@parallel.each(relations.classes) do |cls|
|
104
134
|
filename = path + "/" + cls[:name] + ".html"
|
105
135
|
puts "Writing to #{filename} ..." if @verbose
|
106
|
-
html = Page.new(cls,
|
136
|
+
html = Page.new(cls, relations, cache).to_html
|
107
137
|
File.open(filename, 'w') {|f| f.write(html) }
|
108
138
|
end
|
109
139
|
end
|
110
140
|
|
141
|
+
# Writes JSON export file for each class
|
142
|
+
def write_json(path, relations)
|
143
|
+
exporter = Exporter.new(relations)
|
144
|
+
@parallel.each(relations.classes) do |cls|
|
145
|
+
filename = path + "/" + cls[:name] + ".json"
|
146
|
+
puts "Writing to #{filename} ..." if @verbose
|
147
|
+
hash = exporter.export(cls)
|
148
|
+
json = JSON.pretty_generate(hash)
|
149
|
+
File.open(filename, 'w') {|f| f.write(json) }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
111
153
|
def copy_template(template_dir, dir)
|
112
154
|
puts "Copying template files to #{dir}..." if @verbose
|
155
|
+
FileUtils.cp_r(template_dir, dir)
|
156
|
+
init_output_dirs(dir)
|
157
|
+
end
|
158
|
+
|
159
|
+
def clear_dir(dir)
|
113
160
|
if File.exists?(dir)
|
114
161
|
FileUtils.rm_r(dir)
|
115
162
|
end
|
116
|
-
|
163
|
+
end
|
164
|
+
|
165
|
+
def init_output_dirs(dir)
|
117
166
|
FileUtils.mkdir(dir + "/output")
|
118
167
|
FileUtils.mkdir(dir + "/source")
|
119
168
|
end
|
data/lib/jsduck/class.rb
CHANGED
@@ -4,9 +4,11 @@ module JsDuck
|
|
4
4
|
# methods on it. Otherwise it acts like Hash, providing the []
|
5
5
|
# method.
|
6
6
|
class Class
|
7
|
-
|
7
|
+
attr_accessor :relations
|
8
|
+
|
9
|
+
def initialize(doc)
|
8
10
|
@doc = doc
|
9
|
-
@
|
11
|
+
@relations = nil
|
10
12
|
end
|
11
13
|
|
12
14
|
def [](key)
|
@@ -15,13 +17,38 @@ module JsDuck
|
|
15
17
|
|
16
18
|
# Returns instance of parent class, or nil if there is none
|
17
19
|
def parent
|
18
|
-
@doc[:extends] ? @
|
20
|
+
@doc[:extends] ? lookup(@doc[:extends]) : nil
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns array of ancestor classes.
|
24
|
+
# Example result when asking ancestors of MyPanel might be:
|
25
|
+
#
|
26
|
+
# [Ext.util.Observable, Ext.Component, Ext.Panel]
|
27
|
+
#
|
28
|
+
def superclasses
|
29
|
+
p = parent
|
30
|
+
p ? p.superclasses + [p] : []
|
19
31
|
end
|
20
32
|
|
21
33
|
# Returns array of mixin class instances.
|
22
34
|
# Returns empty array if no mixins
|
23
35
|
def mixins
|
24
|
-
@doc[:mixins] ? @doc[:mixins].collect {|classname|
|
36
|
+
@doc[:mixins] ? @doc[:mixins].collect {|classname| lookup(classname) }.compact : []
|
37
|
+
end
|
38
|
+
|
39
|
+
# Looks up class object by name
|
40
|
+
# When not found, prints warning message.
|
41
|
+
def lookup(classname)
|
42
|
+
if @relations[classname]
|
43
|
+
@relations[classname]
|
44
|
+
elsif classname != "Object"
|
45
|
+
puts "Warning: Class #{classname} not found in #{@doc[:filename]} line #{@doc[:linenr]}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns copy of @doc hash
|
50
|
+
def to_hash
|
51
|
+
@doc.clone
|
25
52
|
end
|
26
53
|
|
27
54
|
# Returns true when this class inherits from the specified class.
|
data/lib/jsduck/doc_formatter.rb
CHANGED
@@ -5,11 +5,27 @@ module JsDuck
|
|
5
5
|
|
6
6
|
# Formats doc-comments
|
7
7
|
class DocFormatter
|
8
|
-
#
|
8
|
+
# CSS class to add to each link
|
9
|
+
attr_accessor :css_class
|
10
|
+
|
11
|
+
# Template for the href URL.
|
12
|
+
# Can contain %cls% which is replaced with actual classname.
|
13
|
+
# Also '#' and member name is appended to link if needed
|
14
|
+
attr_accessor :url_template
|
15
|
+
|
16
|
+
# Sets up instance to work in context of particular class, so
|
9
17
|
# that when {@link #blah} is encountered it knows that
|
10
18
|
# Context#blah is meant.
|
11
|
-
|
12
|
-
|
19
|
+
attr_accessor :context
|
20
|
+
|
21
|
+
# Maximum length for text that doesn't get shortened, defaults to 120
|
22
|
+
attr_accessor :max_length
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@context = ""
|
26
|
+
@css_class = nil
|
27
|
+
@url_template = "%cls%"
|
28
|
+
@max_length = 120
|
13
29
|
end
|
14
30
|
|
15
31
|
# Replaces {@link Class#member link text} in given string with
|
@@ -17,7 +33,7 @@ module JsDuck
|
|
17
33
|
# attribute links will also contain ext:cls and ext:member
|
18
34
|
# attributes.
|
19
35
|
def replace(input)
|
20
|
-
input.gsub(/\{@link
|
36
|
+
input.gsub(/\{@link\s+(\S*?)(?:\s+(.+?))?\}/m) do
|
21
37
|
target = $1
|
22
38
|
text = $2
|
23
39
|
if target =~ /^(.*)#(.*)$/
|
@@ -28,11 +44,6 @@ module JsDuck
|
|
28
44
|
member = false
|
29
45
|
end
|
30
46
|
|
31
|
-
# Construct link attributes
|
32
|
-
href = " href=\"output/#{cls}.html" + (member ? "#" + cls + "-" + member : "") + '"'
|
33
|
-
ext_cls = ' ext:cls="' + cls + '"'
|
34
|
-
ext_member = member ? ' ext:member="' + member + '"' : ""
|
35
|
-
|
36
47
|
# Construct link text
|
37
48
|
if text
|
38
49
|
text = text
|
@@ -42,10 +53,20 @@ module JsDuck
|
|
42
53
|
text = cls
|
43
54
|
end
|
44
55
|
|
45
|
-
|
56
|
+
link(cls, member, text)
|
46
57
|
end
|
47
58
|
end
|
48
59
|
|
60
|
+
# Creates HTML link to class and/or member
|
61
|
+
def link(cls, member, label)
|
62
|
+
anchor = member ? "#" + member : ""
|
63
|
+
url = @url_template.sub(/%cls%/, cls) + anchor
|
64
|
+
href = ' href="' + url + '"'
|
65
|
+
rel = ' rel="' + cls + anchor + '"'
|
66
|
+
cssCls = @css_class ? ' class="' + @css_class + '"' : ''
|
67
|
+
"<a" + href + rel + cssCls + ">" + label + "</a>"
|
68
|
+
end
|
69
|
+
|
49
70
|
# Formats doc-comment for placement into HTML.
|
50
71
|
# Renders it with Markdown-formatter and replaces @link-s.
|
51
72
|
def format(input)
|
@@ -64,6 +85,36 @@ module JsDuck
|
|
64
85
|
replace(RDiscount.new(input).to_html)
|
65
86
|
end
|
66
87
|
|
88
|
+
# Shortens text if needed.
|
89
|
+
#
|
90
|
+
# 116 chars is also where ext-doc makes its cut, but unlike
|
91
|
+
# ext-doc we only make the cut when there's more than 120 chars.
|
92
|
+
#
|
93
|
+
# This way we don't get stupid expansions like:
|
94
|
+
#
|
95
|
+
# Blah blah blah some text...
|
96
|
+
#
|
97
|
+
# expanding to:
|
98
|
+
#
|
99
|
+
# Blah blah blah some text.
|
100
|
+
#
|
101
|
+
# Ellipsis is only added when input actually gets shortened.
|
102
|
+
def shorten(input)
|
103
|
+
if too_long?(input)
|
104
|
+
strip_tags(input)[0..(@max_length-4)] + "..."
|
105
|
+
else
|
106
|
+
input
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns true when input should get shortened.
|
111
|
+
def too_long?(input)
|
112
|
+
strip_tags(input).length > @max_length
|
113
|
+
end
|
114
|
+
|
115
|
+
def strip_tags(str)
|
116
|
+
str.gsub(/<.*?>/, "")
|
117
|
+
end
|
67
118
|
end
|
68
119
|
|
69
120
|
end
|
data/lib/jsduck/doc_parser.rb
CHANGED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'jsduck/doc_formatter'
|
2
|
+
|
3
|
+
module JsDuck
|
4
|
+
|
5
|
+
# Export class data as hash with :cfg being replace with :cfgs and
|
6
|
+
# including all the inherited members too. Same for :properties,
|
7
|
+
# :methods, and :events.
|
8
|
+
#
|
9
|
+
# Also all the :doc elements will be formatted - converted from
|
10
|
+
# markdown to HTML and @links resolved.
|
11
|
+
class Exporter
|
12
|
+
attr_accessor :relations
|
13
|
+
|
14
|
+
def initialize(relations)
|
15
|
+
@relations = relations
|
16
|
+
@formatter = DocFormatter.new
|
17
|
+
@formatter.css_class = 'docClass'
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns all data in Class object as hash.
|
21
|
+
def export(cls)
|
22
|
+
h = cls.to_hash
|
23
|
+
h[:cfgs] = cls.members(:cfg)
|
24
|
+
h[:properties] = cls.members(:property)
|
25
|
+
h[:methods] = cls.members(:method)
|
26
|
+
h[:events] = cls.members(:event)
|
27
|
+
h.delete(:cfg)
|
28
|
+
h.delete(:property)
|
29
|
+
h.delete(:method)
|
30
|
+
h.delete(:event)
|
31
|
+
h[:component] = cls.inherits_from?("Ext.Component")
|
32
|
+
h[:superclasses] = cls.superclasses.collect {|c| c.full_name }
|
33
|
+
h[:subclasses] = @relations.subclasses(cls).collect {|c| c.full_name }
|
34
|
+
h[:mixedInto] = @relations.mixed_into(cls).collect {|c| c.full_name }
|
35
|
+
format_class(h)
|
36
|
+
end
|
37
|
+
|
38
|
+
# converts :doc properties from markdown to html and resolve @links
|
39
|
+
def format_class(c)
|
40
|
+
@formatter.context = c[:name]
|
41
|
+
c[:doc] = @formatter.format(c[:doc]) if c[:doc]
|
42
|
+
[:cfgs, :properties, :methods, :events].each do |type|
|
43
|
+
c[type] = c[type].map {|m| format_member(m) }
|
44
|
+
end
|
45
|
+
c
|
46
|
+
end
|
47
|
+
|
48
|
+
def format_member(m)
|
49
|
+
m = m.clone
|
50
|
+
m[:doc] = @formatter.format(m[:doc]) if m[:doc]
|
51
|
+
if m[:params] || @formatter.too_long?(m[:doc])
|
52
|
+
m[:shortDoc] = @formatter.shorten(m[:doc])
|
53
|
+
end
|
54
|
+
m[:params] = format_params(m[:params]) if m[:params]
|
55
|
+
m[:return] = format_return(m[:return]) if m[:return]
|
56
|
+
m
|
57
|
+
end
|
58
|
+
|
59
|
+
def format_params(params)
|
60
|
+
params.map do |p|
|
61
|
+
p = p.clone
|
62
|
+
p[:doc] = @formatter.format(p[:doc]) if p[:doc]
|
63
|
+
p
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def format_return(r)
|
68
|
+
r = r.clone
|
69
|
+
r[:doc] = @formatter.format(r[:doc]) if r[:doc]
|
70
|
+
r
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -1,15 +1,21 @@
|
|
1
|
+
require 'jsduck/doc_formatter'
|
2
|
+
|
1
3
|
module JsDuck
|
2
4
|
|
3
5
|
# Creates the inheritance tree shown on class documentation page.
|
4
6
|
class InheritanceTree
|
5
7
|
def initialize(cls)
|
6
8
|
@cls = cls
|
9
|
+
@formatter = DocFormatter.new
|
10
|
+
@formatter.context = cls.full_name
|
11
|
+
@formatter.css_class = 'docClass'
|
12
|
+
@formatter.url_template = 'output/%cls%.html'
|
7
13
|
end
|
8
14
|
|
9
15
|
# Renders the tree using HTML <pre> element
|
10
16
|
def to_html
|
11
17
|
i = -1
|
12
|
-
html =
|
18
|
+
html = (@cls.superclasses + [@cls]).collect do |cls|
|
13
19
|
i += 1
|
14
20
|
make_indent(i) + make_link(cls)
|
15
21
|
end.join("\n")
|
@@ -21,16 +27,6 @@ module JsDuck
|
|
21
27
|
EOHTML
|
22
28
|
end
|
23
29
|
|
24
|
-
# Returns array of the names of ancestor classes for given class.
|
25
|
-
# Including the name of the class itself.
|
26
|
-
# Example result when ascing ancestors of MyPanel might be:
|
27
|
-
#
|
28
|
-
# [MyPanel, Ext.Panel, Ext.Component, Ext.util.Observable]
|
29
|
-
#
|
30
|
-
def ancestors(cls)
|
31
|
-
cls.parent ? [cls] + ancestors(cls.parent) : [cls]
|
32
|
-
end
|
33
|
-
|
34
30
|
def make_indent(level)
|
35
31
|
if level > 0
|
36
32
|
(" " * level) + "<img src='resources/elbow-end.gif' alt=''>"
|
@@ -43,7 +39,7 @@ module JsDuck
|
|
43
39
|
if cls == @cls
|
44
40
|
cls.short_name
|
45
41
|
else
|
46
|
-
|
42
|
+
@formatter.link(cls.full_name, nil, cls.short_name)
|
47
43
|
end
|
48
44
|
end
|
49
45
|
end
|
data/lib/jsduck/lexer.rb
CHANGED
@@ -97,12 +97,12 @@ module JsDuck
|
|
97
97
|
elsif @input.check(/'/)
|
98
98
|
@tokens << {
|
99
99
|
:type => :string,
|
100
|
-
:value =>
|
100
|
+
:value => @input.scan(/'([^'\\]|\\.)*'/).sub(/^'(.*)'$/, "\\1")
|
101
101
|
}
|
102
102
|
elsif @input.check(/"/)
|
103
103
|
@tokens << {
|
104
104
|
:type => :string,
|
105
|
-
:value =>
|
105
|
+
:value => @input.scan(/"([^"\\]|\\.)*"/).sub(/^"(.*)"$/, "\\1")
|
106
106
|
}
|
107
107
|
elsif @input.check(/\//)
|
108
108
|
# Several things begin with dash:
|
data/lib/jsduck/long_params.rb
CHANGED
@@ -6,7 +6,10 @@ module JsDuck
|
|
6
6
|
# for use in documentation body.
|
7
7
|
class LongParams
|
8
8
|
def initialize(cls)
|
9
|
-
@formatter = DocFormatter.new(
|
9
|
+
@formatter = DocFormatter.new()
|
10
|
+
@formatter.context = cls.full_name
|
11
|
+
@formatter.css_class = 'docClass'
|
12
|
+
@formatter.url_template = 'output/%cls%.html'
|
10
13
|
end
|
11
14
|
|
12
15
|
def render(params)
|
@@ -0,0 +1,57 @@
|
|
1
|
+
|
2
|
+
module JsDuck
|
3
|
+
|
4
|
+
# Creates list of all members in all classes that is used by the
|
5
|
+
# searching feature in UI.
|
6
|
+
class Members
|
7
|
+
# Given list of class documentation objects returns an array of
|
8
|
+
# hashes describing all the members.
|
9
|
+
def create(docs)
|
10
|
+
list = []
|
11
|
+
docs.each do |cls|
|
12
|
+
[:cfg, :property, :method, :event].each do |type|
|
13
|
+
cls.members(type).each do |m|
|
14
|
+
list << member_node(m, cls)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
list
|
19
|
+
end
|
20
|
+
|
21
|
+
# Creates structure representing one member
|
22
|
+
def member_node(member, cls)
|
23
|
+
return {
|
24
|
+
:cls => cls.full_name,
|
25
|
+
:member => member[:name],
|
26
|
+
:type => member[:tagname],
|
27
|
+
:doc => short_desc(member[:doc])
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def short_desc(str)
|
32
|
+
tagless = first_sentence(strip_tags(strip_links(str)))
|
33
|
+
if tagless.length > 120
|
34
|
+
short_doc = tagless[0..116]
|
35
|
+
ellipsis = tagless.length > short_doc.length ? "..." : ""
|
36
|
+
tagless[0..116] + ellipsis
|
37
|
+
else
|
38
|
+
tagless
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def strip_tags(str)
|
43
|
+
str.gsub(/<.*?>/, "")
|
44
|
+
end
|
45
|
+
|
46
|
+
def strip_links(str)
|
47
|
+
str = str.gsub(/\{@link +(\S*?)(?: +(.+?))?\}/, "\\1")
|
48
|
+
str = str.gsub(/#/, ".")
|
49
|
+
end
|
50
|
+
|
51
|
+
def first_sentence(str)
|
52
|
+
str.sub(/\A(.+?\.)\s.*\Z/m, "\\1")
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
data/lib/jsduck/merger.rb
CHANGED
@@ -248,10 +248,13 @@ module JsDuck
|
|
248
248
|
[implicit.length, explicit.length].max.times do |i|
|
249
249
|
im = implicit[i] || {}
|
250
250
|
ex = explicit[i] || {}
|
251
|
+
doc = ex[:doc] || im[:doc] || ""
|
251
252
|
params << {
|
252
253
|
:type => ex[:type] || im[:type] || "Object",
|
253
254
|
:name => ex[:name] || im[:name] || "",
|
254
|
-
:doc =>
|
255
|
+
:doc => doc,
|
256
|
+
# convert to boolean for JavaScript export, otherwise it's 0 or nil
|
257
|
+
:optional => !!(doc =~ /\(optional\)/),
|
255
258
|
}
|
256
259
|
end
|
257
260
|
params
|
data/lib/jsduck/method_table.rb
CHANGED
@@ -14,6 +14,10 @@ module JsDuck
|
|
14
14
|
@row_class = "method-row"
|
15
15
|
@short_params = ShortParams.new
|
16
16
|
@long_params = LongParams.new(@cls)
|
17
|
+
@formatter = DocFormatter.new()
|
18
|
+
@formatter.context = @cls.full_name
|
19
|
+
@formatter.css_class = 'docClass'
|
20
|
+
@formatter.url_template = 'output/%cls%.html'
|
17
21
|
end
|
18
22
|
|
19
23
|
def signature_suffix(item)
|
@@ -33,7 +37,7 @@ module JsDuck
|
|
33
37
|
|
34
38
|
def render_return(item)
|
35
39
|
type = item[:return][:type]
|
36
|
-
doc = item[:return][:doc]
|
40
|
+
doc = @formatter.format(item[:return][:doc])
|
37
41
|
if type == "void" && doc.length == 0
|
38
42
|
"<ul><li>void</li></ul>"
|
39
43
|
else
|
data/lib/jsduck/page.rb
CHANGED
@@ -12,14 +12,17 @@ module JsDuck
|
|
12
12
|
# Initializes doc page generator
|
13
13
|
#
|
14
14
|
# - cls : the Class object for which to generate documentation
|
15
|
-
# -
|
15
|
+
# - relations : access to subclasses, mixins, etc
|
16
16
|
# - cache : cache for already generated HTML rows for class members
|
17
17
|
#
|
18
|
-
def initialize(cls,
|
18
|
+
def initialize(cls, relations, cache = {})
|
19
19
|
@cls = cls
|
20
|
-
@
|
20
|
+
@relations = relations
|
21
21
|
@cache = cache
|
22
|
-
@formatter = DocFormatter.new
|
22
|
+
@formatter = DocFormatter.new
|
23
|
+
@formatter.context = cls.full_name
|
24
|
+
@formatter.css_class = 'docClass'
|
25
|
+
@formatter.url_template = 'output/%cls%.html'
|
23
26
|
end
|
24
27
|
|
25
28
|
def to_html
|
@@ -50,36 +53,49 @@ module JsDuck
|
|
50
53
|
def abstract
|
51
54
|
[
|
52
55
|
"<table cellspacing='0'>",
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
row("Extends:", extends_link),
|
57
|
+
classes_row("Mixins:", @cls.mixins),
|
58
|
+
row("Defind In:", file_link),
|
59
|
+
classes_row("Subclasses:", @relations.subclasses(@cls)),
|
60
|
+
classes_row("Mixed into:", @relations.mixed_into(@cls)),
|
61
|
+
boolean_row("xtype:", @cls[:xtype]),
|
62
|
+
boolean_row("Author:", @cls[:author]),
|
59
63
|
"</table>",
|
60
64
|
].join("\n")
|
61
65
|
end
|
62
66
|
|
63
67
|
def class_link(class_name, label=nil)
|
64
68
|
label = label || class_name
|
65
|
-
|
69
|
+
@formatter.link(class_name, nil, label || class_name)
|
66
70
|
end
|
67
71
|
|
68
72
|
def file_link
|
69
73
|
"<a href='source/#{@cls[:href]}'>#{File.basename(@cls[:filename])}</a>"
|
70
74
|
end
|
71
75
|
|
72
|
-
def
|
73
|
-
|
74
|
-
|
76
|
+
def extends_link
|
77
|
+
if @cls[:extends]
|
78
|
+
@relations[@cls[:extends]] ? class_link(@cls[:extends]) : @cls[:extends]
|
79
|
+
else
|
80
|
+
"Object"
|
81
|
+
end
|
75
82
|
end
|
76
83
|
|
77
|
-
def
|
78
|
-
|
79
|
-
|
84
|
+
def classes_row(label, classes)
|
85
|
+
if classes.length > 0
|
86
|
+
classes = classes.sort {|a, b| a.short_name <=> b.short_name }
|
87
|
+
html = classes.collect {|cls| class_link(cls.full_name, cls.short_name) }.join(", ")
|
88
|
+
row(label, html)
|
89
|
+
else
|
90
|
+
""
|
91
|
+
end
|
80
92
|
end
|
81
93
|
|
82
|
-
def
|
94
|
+
def boolean_row(label, item)
|
95
|
+
item ? row(label, item) : ""
|
96
|
+
end
|
97
|
+
|
98
|
+
def row(label, info)
|
83
99
|
"<tr><td class='label'>#{label}</td><td class='hd-info'>#{info}</td></tr>"
|
84
100
|
end
|
85
101
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'parallel'
|
2
|
+
|
3
|
+
module JsDuck
|
4
|
+
|
5
|
+
# Wrapper around the parallel gem that falls back to simple
|
6
|
+
# Array#map and Array#each when :in_processes => 0 specified.
|
7
|
+
class ParallelWrap
|
8
|
+
|
9
|
+
# Takes config object for parallel
|
10
|
+
def initialize(cfg = {})
|
11
|
+
@cfg = cfg
|
12
|
+
end
|
13
|
+
|
14
|
+
def each(arr, &block)
|
15
|
+
if @cfg[:in_processes] == 0
|
16
|
+
arr.each &block
|
17
|
+
else
|
18
|
+
Parallel.each(arr, @cfg, &block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def map(arr, &block)
|
23
|
+
if @cfg[:in_processes] == 0
|
24
|
+
arr.map &block
|
25
|
+
else
|
26
|
+
Parallel.map(arr, @cfg, &block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module JsDuck
|
2
|
+
|
3
|
+
# Provides information about relations between classes.
|
4
|
+
#
|
5
|
+
# Also provides a place to look up classes by name.
|
6
|
+
#
|
7
|
+
# The constructor is initialized with array of all available
|
8
|
+
# classes.
|
9
|
+
class Relations
|
10
|
+
# Returns list of all classes
|
11
|
+
attr_reader :classes
|
12
|
+
|
13
|
+
def initialize(classes = [])
|
14
|
+
@classes = classes
|
15
|
+
|
16
|
+
# First build class lookup table; building lookup tables for
|
17
|
+
# mixins and subclasses will depend on that.
|
18
|
+
@lookup = {}
|
19
|
+
@classes.each do |cls|
|
20
|
+
@lookup[cls.full_name] = cls
|
21
|
+
cls.relations = self
|
22
|
+
end
|
23
|
+
|
24
|
+
@subs = {}
|
25
|
+
@mixes = {}
|
26
|
+
@classes.each do |cls|
|
27
|
+
reg_subclasses(cls)
|
28
|
+
reg_mixed_into(cls)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Looks up class by name, nil if not found
|
33
|
+
def [](classname)
|
34
|
+
@lookup[classname]
|
35
|
+
end
|
36
|
+
|
37
|
+
def reg_subclasses(cls)
|
38
|
+
if !cls.parent
|
39
|
+
# do nothing
|
40
|
+
elsif @subs[cls.parent.full_name]
|
41
|
+
@subs[cls.parent.full_name] << cls
|
42
|
+
else
|
43
|
+
@subs[cls.parent.full_name] = [cls]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns subclasses of particular class, empty array if none
|
48
|
+
def subclasses(cls)
|
49
|
+
@subs[cls.full_name] || []
|
50
|
+
end
|
51
|
+
|
52
|
+
def reg_mixed_into(cls)
|
53
|
+
cls.mixins.each do |mix|
|
54
|
+
if @mixes[mix.full_name]
|
55
|
+
@mixes[mix.full_name] << cls
|
56
|
+
else
|
57
|
+
@mixes[mix.full_name] = [cls]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns classes having particular mixin, empty array if none
|
63
|
+
def mixed_into(cls)
|
64
|
+
@mixes[cls.full_name] || []
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
data/lib/jsduck/short_params.rb
CHANGED
@@ -13,16 +13,12 @@ module JsDuck
|
|
13
13
|
|
14
14
|
def render_single(param)
|
15
15
|
str = "<code>#{param[:type]} #{param[:name]}</code>"
|
16
|
-
if optional
|
16
|
+
if param[:optional]
|
17
17
|
"<span title='Optional' class='optional'>[" + str + "]</span>"
|
18
18
|
else
|
19
19
|
str
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
23
|
-
def optional?(param)
|
24
|
-
return param[:doc] =~ /\(optional\)/
|
25
|
-
end
|
26
22
|
end
|
27
23
|
|
28
24
|
end
|
@@ -8,16 +8,21 @@ module JsDuck
|
|
8
8
|
class SourceFormatter
|
9
9
|
|
10
10
|
# Initializes SourceFormatter to the directory where
|
11
|
-
# HTML-formatted source files will be placed
|
12
|
-
|
11
|
+
# HTML-formatted source files will be placed.
|
12
|
+
#
|
13
|
+
# formatter can be either :format_page or :format_pre; with the
|
14
|
+
# first one the whole HTML page is created, otherwise just a
|
15
|
+
# contents of <pre> element.
|
16
|
+
def initialize(output_dir, formatter = :format_page)
|
13
17
|
@output_dir = output_dir
|
18
|
+
@formatter = formatter
|
14
19
|
end
|
15
20
|
|
16
21
|
# Converts source to HTML and writes into file in output
|
17
22
|
# directory. It returns the name of the file that it wrote.
|
18
23
|
def write(source, filename)
|
19
24
|
fname = uniq_html_filename(filename)
|
20
|
-
File.open(fname, 'w') {|f| f.write(
|
25
|
+
File.open(fname, 'w') {|f| f.write(self.send(@formatter, source)) }
|
21
26
|
fname
|
22
27
|
end
|
23
28
|
|
@@ -36,7 +41,7 @@ module JsDuck
|
|
36
41
|
end
|
37
42
|
|
38
43
|
# Returns full source for HTML page
|
39
|
-
def
|
44
|
+
def format_page(source)
|
40
45
|
return <<-EOHTML
|
41
46
|
<!DOCTYPE html>
|
42
47
|
<html>
|
data/lib/jsduck/table.rb
CHANGED
@@ -20,7 +20,10 @@ module JsDuck
|
|
20
20
|
def initialize(cls, cache={})
|
21
21
|
@cls = cls
|
22
22
|
@cache = cache
|
23
|
-
@formatter = DocFormatter.new
|
23
|
+
@formatter = DocFormatter.new
|
24
|
+
@formatter.context = cls.full_name
|
25
|
+
@formatter.css_class = 'docClass'
|
26
|
+
@formatter.url_template = 'output/%cls%.html'
|
24
27
|
end
|
25
28
|
|
26
29
|
def to_html
|
@@ -75,11 +78,7 @@ module JsDuck
|
|
75
78
|
end
|
76
79
|
|
77
80
|
def member_link(item)
|
78
|
-
|
79
|
-
member = item[:name]
|
80
|
-
"<a href='output/#{cls}.html##{member}' " +
|
81
|
-
"ext:member='##{member}' " +
|
82
|
-
"ext:cls='#{cls}'>#{Class.short_name(cls)}</a>"
|
81
|
+
@formatter.link(item[:member], item[:name], Class.short_name(item[:member]))
|
83
82
|
end
|
84
83
|
|
85
84
|
def signature(item)
|
@@ -88,24 +87,11 @@ module JsDuck
|
|
88
87
|
return "<a id='#{id}'></a><b><a href='#{src}'>#{item[:name]}</a></b>" + signature_suffix(item)
|
89
88
|
end
|
90
89
|
|
91
|
-
#
|
92
|
-
# ext-doc we only make the cut when there's more than 120 chars.
|
93
|
-
#
|
94
|
-
# This way we don't get stupid expansions like:
|
95
|
-
#
|
96
|
-
# Blah blah blah some text...
|
97
|
-
#
|
98
|
-
# expanding to:
|
99
|
-
#
|
100
|
-
# Blah blah blah some text.
|
101
|
-
#
|
90
|
+
# Creates either expandable or normal doc-entry
|
102
91
|
def expandable_desc(p_doc, e_doc)
|
103
92
|
if expandable?(p_doc, e_doc)
|
104
|
-
|
105
|
-
|
106
|
-
short_doc = tagless[0..116]
|
107
|
-
ellipsis = tagless.length > short_doc.length ? "..." : ""
|
108
|
-
"<div class='short'>#{short_doc}#{ellipsis}</div>" +
|
93
|
+
short_doc = @formatter.shorten(p_doc)
|
94
|
+
"<div class='short'>#{short_doc}</div>" +
|
109
95
|
"<div class='long'>#{p_doc}#{e_doc}</div>"
|
110
96
|
else
|
111
97
|
p_doc
|
@@ -122,11 +108,7 @@ module JsDuck
|
|
122
108
|
end
|
123
109
|
|
124
110
|
def expandable?(p_doc, e_doc)
|
125
|
-
|
126
|
-
end
|
127
|
-
|
128
|
-
def strip_tags(str)
|
129
|
-
str.gsub(/<.*?>/, "")
|
111
|
+
@formatter.too_long?(p_doc) || e_doc.length > 0
|
130
112
|
end
|
131
113
|
|
132
114
|
def inherited?(item)
|
data/template/index.html
CHANGED
@@ -16,6 +16,7 @@
|
|
16
16
|
<script type="text/javascript" src="resources/prettify/prettify.js"></script>
|
17
17
|
<script type="text/javascript" src="resources/docs.js"></script>
|
18
18
|
<script type="text/javascript" src="output/tree.js"></script>
|
19
|
+
<script type="text/javascript" src="output/members.js"></script>
|
19
20
|
</head>
|
20
21
|
<body scroll="no" id="docs">
|
21
22
|
|
data/template/resources/docs.css
CHANGED
@@ -250,10 +250,12 @@ a:hover {
|
|
250
250
|
.icon-event {
|
251
251
|
background-image: url(event.gif) !important;
|
252
252
|
}
|
253
|
+
.icon-cfg,
|
253
254
|
.icon-config {
|
254
255
|
background-image: url(config.gif) !important;
|
255
256
|
}
|
256
|
-
.icon-prop
|
257
|
+
.icon-prop,
|
258
|
+
.icon-property {
|
257
259
|
background-image: url(prop.gif) !important;
|
258
260
|
}
|
259
261
|
.icon-method {
|
data/template/resources/docs.js
CHANGED
@@ -75,7 +75,7 @@ Ext.extend(ApiPanel, Ext.tree.TreePanel, {
|
|
75
75
|
handler: function(){ this.root.collapse(true); },
|
76
76
|
scope: this
|
77
77
|
}]
|
78
|
-
})
|
78
|
+
});
|
79
79
|
ApiPanel.superclass.initComponent.call(this);
|
80
80
|
},
|
81
81
|
filterTree: function(t, e){
|
@@ -226,21 +226,20 @@ DocPanel = Ext.extend(Ext.Panel, {
|
|
226
226
|
MainPanel = function(){
|
227
227
|
|
228
228
|
this.searchStore = new Ext.data.Store({
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
['cls', 'member', 'type', 'doc']
|
236
|
-
)
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
});
|
229
|
+
sortInfo: {
|
230
|
+
field: 'member',
|
231
|
+
direction: 'ASC'
|
232
|
+
},
|
233
|
+
reader: new Ext.data.JsonReader({
|
234
|
+
root: 'data',
|
235
|
+
fields: ['cls', 'member', 'type', 'doc']
|
236
|
+
})
|
237
|
+
});
|
238
|
+
this.searchStore.loadData(Docs.membersData);
|
239
|
+
this.searchStore.filterBy(function(r) {
|
240
|
+
return false;
|
241
|
+
});
|
242
|
+
|
244
243
|
|
245
244
|
MainPanel.superclass.constructor.call(this, {
|
246
245
|
id:'doc-body',
|
@@ -256,7 +255,7 @@ MainPanel = function(){
|
|
256
255
|
items: {
|
257
256
|
id:'welcome-panel',
|
258
257
|
title: 'API Home',
|
259
|
-
autoLoad: {url: 'welcome.html', callback: this.initSearch, scope: this},
|
258
|
+
autoLoad: {url: 'welcome.html', callback: this.initSearch, scope: this, delay: 100},
|
260
259
|
iconCls:'icon-docs',
|
261
260
|
autoScroll: true,
|
262
261
|
tbar: [
|
@@ -291,18 +290,17 @@ Ext.extend(MainPanel, Ext.TabPanel, {
|
|
291
290
|
},
|
292
291
|
|
293
292
|
onClick: function(e, target){
|
294
|
-
if(target = e.getTarget('a:not(.exi)', 3)){
|
295
|
-
var cls = Ext.fly(target).getAttributeNS('ext', 'cls');
|
293
|
+
if((target = e.getTarget('a:not(.exi)', 3))){
|
296
294
|
e.stopEvent();
|
297
|
-
if(
|
298
|
-
var
|
299
|
-
this.loadClass(target.href,
|
295
|
+
if(/\bdocClass\b/.test(target.className)){
|
296
|
+
var m = target.rel.split("#");
|
297
|
+
this.loadClass(target.href, m[0], m[1]);
|
300
298
|
}else if(target.className == 'inner-link'){
|
301
299
|
this.getActiveTab().scrollToSection(target.href.split('#')[1]);
|
302
300
|
}else{
|
303
301
|
window.open(target.href);
|
304
302
|
}
|
305
|
-
}else if(target = e.getTarget('.micon', 2)){
|
303
|
+
}else if((target = e.getTarget('.micon', 2))){
|
306
304
|
e.stopEvent();
|
307
305
|
var tr = Ext.fly(target.parentNode);
|
308
306
|
if(tr.hasClass('expandable')){
|
@@ -343,17 +341,18 @@ Ext.extend(MainPanel, Ext.TabPanel, {
|
|
343
341
|
var resultTpl = new Ext.XTemplate(
|
344
342
|
'<tpl for=".">',
|
345
343
|
'<div class="search-item">',
|
346
|
-
'<a class="member"
|
347
|
-
'<img src="
|
344
|
+
'<a class="member docClass" rel="{cls}#{member}" href="output/{cls}.html">',
|
345
|
+
'<img src="resources/images/default/s.gif" class="item-icon icon-{type}"/>{member}',
|
348
346
|
'</a> ',
|
349
|
-
'<a class="cls"
|
347
|
+
'<a class="cls docClass" rel="{cls}" href="output/{cls}.html">{cls}</a>',
|
350
348
|
'<p>{doc}</p>',
|
351
349
|
'</div></tpl>'
|
352
350
|
);
|
353
|
-
|
351
|
+
|
354
352
|
var p = new Ext.DataView({
|
355
|
-
|
353
|
+
applyTo: Ext.get('search') ? 'search' : Ext.getCmp('welcome-panel').body,
|
356
354
|
tpl: resultTpl,
|
355
|
+
deferEmptyText: false,
|
357
356
|
loadingText:'Searching...',
|
358
357
|
store: this.searchStore,
|
359
358
|
itemSelector: 'div.search-item',
|
@@ -452,12 +451,13 @@ Ext.app.SearchField = Ext.extend(Ext.form.TwinTriggerField, {
|
|
452
451
|
|
453
452
|
onTrigger1Click : function(){
|
454
453
|
if(this.hasSearch){
|
455
|
-
this.store.
|
456
|
-
|
457
|
-
|
454
|
+
this.store.filterBy(function(r) {
|
455
|
+
return false;
|
456
|
+
});
|
457
|
+
this.el.dom.value = '';
|
458
458
|
this.triggers[0].hide();
|
459
459
|
this.hasSearch = false;
|
460
|
-
|
460
|
+
this.focus();
|
461
461
|
}
|
462
462
|
},
|
463
463
|
|
@@ -471,12 +471,24 @@ Ext.app.SearchField = Ext.extend(Ext.form.TwinTriggerField, {
|
|
471
471
|
Ext.Msg.alert('Invalid Search', 'You must enter a minimum of 2 characters to search the API');
|
472
472
|
return;
|
473
473
|
}
|
474
|
-
|
475
|
-
|
476
|
-
|
474
|
+
|
475
|
+
var type = Ext.getCmp('search-type').getValue();
|
476
|
+
this.store.filter("member", this.createRegex(type, v));
|
477
|
+
|
477
478
|
this.hasSearch = true;
|
478
479
|
this.triggers[0].show();
|
479
480
|
this.focus();
|
481
|
+
},
|
482
|
+
|
483
|
+
createRegex: function(type, text) {
|
484
|
+
var safeText = Ext.escapeRe(text);
|
485
|
+
if (type === 'Starts with') {
|
486
|
+
return new RegExp("^" + safeText, "i");
|
487
|
+
} else if (type === 'Ends with') {
|
488
|
+
return new RegExp(safeText + "$", "i");
|
489
|
+
} else {
|
490
|
+
return new RegExp(safeText, "i");
|
491
|
+
}
|
480
492
|
}
|
481
493
|
});
|
482
494
|
|
@@ -548,6 +560,8 @@ Ext.extend(Ext.ux.SelectBox, Ext.form.ComboBox, {
|
|
548
560
|
this.selectPrevPage();
|
549
561
|
e.stopEvent();
|
550
562
|
return;
|
563
|
+
default:
|
564
|
+
break;
|
551
565
|
}
|
552
566
|
|
553
567
|
// skip special keys other than the shift key
|
metadata
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsduck
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 1
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: "0.
|
8
|
+
- 5
|
9
|
+
version: "0.5"
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Rene Saarsoo
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-
|
17
|
+
date: 2011-03-29 00:00:00 +03:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -81,17 +81,20 @@ files:
|
|
81
81
|
- lib/jsduck/doc_formatter.rb
|
82
82
|
- lib/jsduck/doc_parser.rb
|
83
83
|
- lib/jsduck/event_table.rb
|
84
|
+
- lib/jsduck/exporter.rb
|
84
85
|
- lib/jsduck/inheritance_tree.rb
|
85
86
|
- lib/jsduck/lexer.rb
|
86
87
|
- lib/jsduck/long_params.rb
|
88
|
+
- lib/jsduck/members.rb
|
87
89
|
- lib/jsduck/merger.rb
|
88
90
|
- lib/jsduck/method_table.rb
|
89
91
|
- lib/jsduck/page.rb
|
92
|
+
- lib/jsduck/parallel_wrap.rb
|
90
93
|
- lib/jsduck/parser.rb
|
91
94
|
- lib/jsduck/property_table.rb
|
95
|
+
- lib/jsduck/relations.rb
|
92
96
|
- lib/jsduck/short_params.rb
|
93
97
|
- lib/jsduck/source_formatter.rb
|
94
|
-
- lib/jsduck/subclasses.rb
|
95
98
|
- lib/jsduck/table.rb
|
96
99
|
- lib/jsduck/timer.rb
|
97
100
|
- lib/jsduck/tree.rb
|
data/lib/jsduck/subclasses.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
module JsDuck
|
2
|
-
|
3
|
-
# Provides information about direct descendants of particular class.
|
4
|
-
#
|
5
|
-
# The constructor is initialized with array of all available
|
6
|
-
# classes. Then through [] method subclasses of particlular class
|
7
|
-
# can be asked for.
|
8
|
-
class Subclasses
|
9
|
-
def initialize(classes)
|
10
|
-
@subs = {}
|
11
|
-
classes.each do |cls|
|
12
|
-
if !cls.parent
|
13
|
-
# do nothing
|
14
|
-
elsif @subs[cls.parent.full_name]
|
15
|
-
@subs[cls.parent.full_name] << cls
|
16
|
-
else
|
17
|
-
@subs[cls.parent.full_name] = [cls]
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def [](cls)
|
23
|
-
@subs[cls.full_name]
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|