jsduck 0.4 → 0.5
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.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
|