@qubit-ltd/jsdoc-theme 1.3.6 → 1.5.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.
- package/README.md +78 -6
- package/i18n/en.json +1 -0
- package/i18n/zh.json +1 -0
- package/package.json +1 -1
- package/publish.js +7 -7
- package/tmpl/container.tmpl +110 -7
- package/tmpl/method.tmpl +13 -7
- package/tmpl/properties.tmpl +120 -97
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# qubit-jsdoc-theme
|
|
2
2
|
|
|
3
|
-
[](https://github.com/Haixing-Hu/qubit-jsdoc-theme) [](https://github.com/Haixing-Hu/qubit-jsdoc-theme/fork) ](https://github.com/Haixing-Hu/qubit-jsdoc-theme) [](https://github.com/Haixing-Hu/qubit-jsdoc-theme/fork)  [](https://github.com/Haixing-Hu/qubit-jsdoc-theme/issues) [](https://github.com/Haixing-Hu/qubit-jsdoc-theme/graphs/contributors) [](https://github.com/Haixing-Hu/qubit-jsdoc-theme/blob/master/LICENSE)
|
|
4
4
|
<br>
|
|
5
5
|
|
|
6
6
|
**Based on [clean-jsdoc-theme](https://github.com/ankitskvmdam/clean-jsdoc-theme) v4.3.0**
|
|
@@ -10,9 +10,12 @@
|
|
|
10
10
|
## Enhanced Features (New in qubit-jsdoc-theme)
|
|
11
11
|
|
|
12
12
|
- **🆕 Smart Properties Table:** Automatically generates a dedicated "Properties" section for classes, displaying all class properties in a clean table format with type information and descriptions derived from individual field JSDoc comments.
|
|
13
|
+
- **🆕 Static/Instance Property Separation:** Intelligently separates static and instance properties into distinct sections, with automatic scope detection and fallback logic for accurate classification.
|
|
14
|
+
- **🆕 Getter/Setter Pair Merging:** Automatically detects and merges getter/setter pairs into single table entries, displaying combined descriptions and access type indicators.
|
|
13
15
|
- **🆕 Intelligent Constructor Detection:** Only displays the "Constructor" section when a class has explicit constructor documentation, avoiding empty constructor sections for classes without custom constructors.
|
|
14
16
|
- **🆕 Field-Level JSDoc Support:** Properties table is populated directly from `@type` annotations on individual class fields, eliminating the need for redundant `@property` tags in class-level JSDoc.
|
|
15
17
|
- **🆕 Clean Member Organization:** Properties are displayed in their own dedicated section, while the "Members" section can be configured to show only methods, avoiding duplication.
|
|
18
|
+
- **🆕 Enhanced Mixin Support:** Automatically displays methods inherited from mixin classes when using `@mixes` JSDoc tags, providing complete documentation of mixed-in functionality with proper inheritance attribution.
|
|
16
19
|
- **🆕 Internationalization (i18n):** Full support for multiple languages with comprehensive translation of all UI elements, section headings, table headers, and navigation tooltips.
|
|
17
20
|
- **🆕 Homepage Navigation:** Added a "Back to Homepage" button in the top navigation bar for easy navigation between class documentation and the main documentation index.
|
|
18
21
|
- **🆕 Enhanced Tooltips:** All navigation buttons include internationalized tooltips that adapt to the selected language.
|
|
@@ -32,8 +35,10 @@
|
|
|
32
35
|
The enhanced features of `qubit-jsdoc-theme` include:
|
|
33
36
|
|
|
34
37
|
1. **Smart Properties Table**: Automatically generated from field-level `@type` annotations
|
|
35
|
-
2. **
|
|
36
|
-
3. **
|
|
38
|
+
2. **Static/Instance Property Separation**: Properties are automatically categorized and displayed in separate sections
|
|
39
|
+
3. **Getter/Setter Pair Merging**: Related accessor methods are intelligently combined in the properties table
|
|
40
|
+
4. **Intelligent Constructor Detection**: Only shows constructor section when explicitly documented
|
|
41
|
+
5. **Clean Organization**: Properties and methods are clearly separated with enhanced categorization
|
|
37
42
|
|
|
38
43
|
For the base theme features and styling, you can reference the original [clean-jsdoc-theme demo](https://ankdev.me/clean-jsdoc-theme/v4).
|
|
39
44
|
|
|
@@ -96,6 +101,13 @@ Here's how to document your JavaScript classes to take advantage of the enhanced
|
|
|
96
101
|
* @author John Doe
|
|
97
102
|
*/
|
|
98
103
|
class User {
|
|
104
|
+
/**
|
|
105
|
+
* Total number of users created
|
|
106
|
+
* @type {number}
|
|
107
|
+
* @static
|
|
108
|
+
*/
|
|
109
|
+
static userCount = 0;
|
|
110
|
+
|
|
99
111
|
/**
|
|
100
112
|
* User's unique identifier
|
|
101
113
|
* @type {string}
|
|
@@ -120,6 +132,24 @@ class User {
|
|
|
120
132
|
*/
|
|
121
133
|
isActive;
|
|
122
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Get user's full display information
|
|
137
|
+
* @type {string}
|
|
138
|
+
*/
|
|
139
|
+
get displayInfo() {
|
|
140
|
+
return `${this.name} (${this.email})`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Set user's full display information
|
|
145
|
+
* @type {string}
|
|
146
|
+
*/
|
|
147
|
+
set displayInfo(value) {
|
|
148
|
+
const parts = value.split(' (');
|
|
149
|
+
this.name = parts[0];
|
|
150
|
+
this.email = parts[1]?.replace(')', '') || '';
|
|
151
|
+
}
|
|
152
|
+
|
|
123
153
|
/**
|
|
124
154
|
* Creates a new user instance
|
|
125
155
|
* @param {string} name - The user's name
|
|
@@ -129,6 +159,7 @@ class User {
|
|
|
129
159
|
this.name = name;
|
|
130
160
|
this.email = email;
|
|
131
161
|
this.isActive = true;
|
|
162
|
+
User.userCount++;
|
|
132
163
|
}
|
|
133
164
|
|
|
134
165
|
/**
|
|
@@ -143,9 +174,10 @@ class User {
|
|
|
143
174
|
```
|
|
144
175
|
|
|
145
176
|
This will generate documentation with:
|
|
146
|
-
-
|
|
147
|
-
-
|
|
148
|
-
-
|
|
177
|
+
- **Static Properties section**: Showing `userCount` and other static properties
|
|
178
|
+
- **Instance Properties section**: Showing `id`, `name`, `email`, `isActive` and merged `displayInfo` (getter/setter)
|
|
179
|
+
- **Constructor section**: Only displayed when constructor has documentation
|
|
180
|
+
- **Members section**: For methods like `activate()` (properties are excluded to avoid duplication)
|
|
149
181
|
|
|
150
182
|
## Example JSDoc Config
|
|
151
183
|
|
|
@@ -705,11 +737,51 @@ Don't forget to add the following in your jsdoc config file, otherwise toc will
|
|
|
705
737
|
|
|
706
738
|
## Changelog
|
|
707
739
|
|
|
740
|
+
### v1.5.0 (2025-01-XX)
|
|
741
|
+
|
|
742
|
+
**Advanced Property Management & Enhanced Documentation Features**
|
|
743
|
+
|
|
744
|
+
#### 🔧 New Features
|
|
745
|
+
- **Static/Instance Property Separation**: Automatically separates static and instance properties into distinct sections with intelligent scope detection
|
|
746
|
+
- **Getter/Setter Pair Merging**: Smart detection and merging of getter/setter pairs into unified table entries with combined descriptions
|
|
747
|
+
- **Enhanced Scope Detection**: Improved logic for detecting property scope using JSDoc's built-in detection with fallback heuristics
|
|
748
|
+
- **Access Type Indicators**: Clear visual indicators for property access types (property, getter, setter, getter/setter)
|
|
749
|
+
|
|
750
|
+
#### 🛠️ Technical Improvements
|
|
751
|
+
- **Advanced Template Logic**: Enhanced `container.tmpl` with sophisticated property categorization and merging algorithms
|
|
752
|
+
- **Improved Properties Template**: Updated `properties.tmpl` to support separate rendering of static and instance properties
|
|
753
|
+
- **Fallback Scope Detection**: Added longname pattern analysis for accurate scope detection when JSDoc's built-in detection fails
|
|
754
|
+
- **Bilingual Section Headers**: Support for both English and Chinese section headers in property tables
|
|
755
|
+
|
|
756
|
+
#### 📖 Documentation Updates
|
|
757
|
+
- **Enhanced Usage Examples**: Updated examples to demonstrate static properties and getter/setter documentation
|
|
758
|
+
- **Feature Documentation**: Comprehensive documentation for new property management features
|
|
759
|
+
|
|
760
|
+
### v1.4.0 (2025-01-XX)
|
|
761
|
+
|
|
762
|
+
**Enhanced Mixin Documentation Support**
|
|
763
|
+
|
|
764
|
+
#### 🔧 New Features
|
|
765
|
+
- **Complete Mixin Method Documentation**: Automatically displays methods inherited from mixin classes when using `@mixes` JSDoc tags
|
|
766
|
+
- **Proper Inheritance Attribution**: Methods from mixin classes are displayed with clear "Inherited from [MixinClass]" labels
|
|
767
|
+
- **Full Method Documentation**: Includes complete parameter descriptions, return values, and method documentation from mixin classes
|
|
768
|
+
- **Seamless Integration**: Works transparently with existing `@mixes` tags without requiring code changes
|
|
769
|
+
|
|
770
|
+
#### 🛠️ Technical Improvements
|
|
771
|
+
- **Enhanced Template Logic**: Updated `container.tmpl` to collect and display methods from mixed-in classes
|
|
772
|
+
- **Dynamic Method Collection**: Automatically searches for methods in classes specified by `@mixes` tags
|
|
773
|
+
- **Inheritance Flag Support**: Properly marks mixin methods as inherited for correct documentation formatting
|
|
774
|
+
|
|
775
|
+
#### 📖 Documentation Updates
|
|
776
|
+
- **Updated Examples**: Enhanced usage examples to demonstrate mixin documentation features
|
|
777
|
+
- **Feature Documentation**: Added comprehensive documentation for the new mixin method display functionality
|
|
778
|
+
|
|
708
779
|
### v1.2.0 (2025-01-XX)
|
|
709
780
|
|
|
710
781
|
**Major Update - Internationalization & Navigation Enhancements**
|
|
711
782
|
|
|
712
783
|
#### 🌍 New Features
|
|
784
|
+
- **Enhanced Mixin Documentation**: Automatic detection and display of methods inherited from mixin classes when using `@mixes` JSDoc tags, with proper "Inherited from" attribution
|
|
713
785
|
- **Full Internationalization (i18n)**: Complete support for multiple languages with comprehensive translation system
|
|
714
786
|
- **Homepage Navigation Button**: Added "Back to Homepage" button in top navigation bar for easy navigation
|
|
715
787
|
- **Internationalized Tooltips**: All navigation buttons now include language-aware tooltips
|
package/i18n/en.json
CHANGED
package/i18n/zh.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qubit-ltd/jsdoc-theme",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "A customized JSDoc theme based on clean-jsdoc-theme, enhanced with properties table and constructor detection features for Qubit projects.",
|
|
5
5
|
"main": "publish.js",
|
|
6
6
|
"author": "Haixing Hu (starfish.hu@gmail.com)",
|
package/publish.js
CHANGED
|
@@ -555,7 +555,7 @@ function buildSidebar(members) {
|
|
|
555
555
|
|
|
556
556
|
const sections = {
|
|
557
557
|
[SECTION_TYPE.Modules]: buildSidebarMembers({
|
|
558
|
-
itemHeading: "Modules",
|
|
558
|
+
itemHeading: i18n.t("module", "Modules"),
|
|
559
559
|
items: members.modules,
|
|
560
560
|
itemsSeen: seen,
|
|
561
561
|
linktoFn: linkto,
|
|
@@ -571,7 +571,7 @@ function buildSidebar(members) {
|
|
|
571
571
|
}),
|
|
572
572
|
|
|
573
573
|
[SECTION_TYPE.Externals]: buildSidebarMembers({
|
|
574
|
-
itemHeading: "Externals",
|
|
574
|
+
itemHeading: i18n.t("externals", "Externals"),
|
|
575
575
|
items: members.externals,
|
|
576
576
|
itemsSeen: seen,
|
|
577
577
|
linktoFn: linktoExternal,
|
|
@@ -579,7 +579,7 @@ function buildSidebar(members) {
|
|
|
579
579
|
}),
|
|
580
580
|
|
|
581
581
|
[SECTION_TYPE.Events]: buildSidebarMembers({
|
|
582
|
-
itemHeading: "Events",
|
|
582
|
+
itemHeading: i18n.t("events", "Events"),
|
|
583
583
|
items: members.events,
|
|
584
584
|
itemsSeen: seen,
|
|
585
585
|
linktoFn: linkto,
|
|
@@ -587,7 +587,7 @@ function buildSidebar(members) {
|
|
|
587
587
|
}),
|
|
588
588
|
|
|
589
589
|
[SECTION_TYPE.Namespaces]: buildSidebarMembers({
|
|
590
|
-
itemHeading: "Namespaces",
|
|
590
|
+
itemHeading: i18n.t("namespaces", "Namespaces"),
|
|
591
591
|
items: members.namespaces,
|
|
592
592
|
itemsSeen: seen,
|
|
593
593
|
linktoFn: linkto,
|
|
@@ -595,7 +595,7 @@ function buildSidebar(members) {
|
|
|
595
595
|
}),
|
|
596
596
|
|
|
597
597
|
[SECTION_TYPE.Mixins]: buildSidebarMembers({
|
|
598
|
-
itemHeading: "Mixins",
|
|
598
|
+
itemHeading: i18n.t("mixins", "Mixins"),
|
|
599
599
|
items: members.mixins,
|
|
600
600
|
itemsSeen: seen,
|
|
601
601
|
linktoFn: linkto,
|
|
@@ -603,7 +603,7 @@ function buildSidebar(members) {
|
|
|
603
603
|
}),
|
|
604
604
|
|
|
605
605
|
[SECTION_TYPE.Tutorials]: buildSidebarMembers({
|
|
606
|
-
itemHeading: "Tutorials",
|
|
606
|
+
itemHeading: i18n.t("tutorials", "Tutorials"),
|
|
607
607
|
items: members.tutorials,
|
|
608
608
|
itemsSeen: seenTutorials,
|
|
609
609
|
linktoFn: linktoTutorial,
|
|
@@ -611,7 +611,7 @@ function buildSidebar(members) {
|
|
|
611
611
|
}),
|
|
612
612
|
|
|
613
613
|
[SECTION_TYPE.Interfaces]: buildSidebarMembers({
|
|
614
|
-
itemHeading: "Interfaces",
|
|
614
|
+
itemHeading: i18n.t("interfaces", "Interfaces"),
|
|
615
615
|
items: members.interfaces,
|
|
616
616
|
itemsSeen: seen,
|
|
617
617
|
linktoFn: linkto,
|
package/tmpl/container.tmpl
CHANGED
|
@@ -152,18 +152,103 @@
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
if (allMembers && allMembers.length && allMembers.forEach) {
|
|
155
|
-
//
|
|
156
|
-
var
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
155
|
+
// Separate static and instance properties, merge getter/setter pairs
|
|
156
|
+
var staticProperties = {};
|
|
157
|
+
var instanceProperties = {};
|
|
158
|
+
|
|
159
|
+
allMembers.forEach(function(member) {
|
|
160
|
+
// Use JSDoc's built-in scope detection with fallback logic
|
|
161
|
+
// JSDoc sometimes misidentifies scope in mixin classes, so we add some heuristics
|
|
162
|
+
var isStatic = member.scope === 'static';
|
|
163
|
+
|
|
164
|
+
// Fallback: check longname pattern for static members (uses '.' separator)
|
|
165
|
+
// and instance members (uses '#' separator)
|
|
166
|
+
if (member.longname) {
|
|
167
|
+
var hasStaticSeparator = member.longname.indexOf('.') > member.longname.lastIndexOf('#');
|
|
168
|
+
var hasInstanceSeparator = member.longname.indexOf('#') > member.longname.lastIndexOf('.');
|
|
169
|
+
|
|
170
|
+
if (hasStaticSeparator && !hasInstanceSeparator) {
|
|
171
|
+
isStatic = true;
|
|
172
|
+
} else if (hasInstanceSeparator && !hasStaticSeparator) {
|
|
173
|
+
isStatic = false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
var targetObj = isStatic ? staticProperties : instanceProperties;
|
|
178
|
+
var propName = member.name;
|
|
179
|
+
|
|
180
|
+
if (!targetObj[propName]) {
|
|
181
|
+
targetObj[propName] = {
|
|
182
|
+
name: propName,
|
|
160
183
|
type: member.type,
|
|
161
184
|
description: member.description || '',
|
|
162
185
|
nullable: member.nullable,
|
|
163
186
|
optional: member.optional,
|
|
164
|
-
defaultvalue: member.defaultvalue
|
|
187
|
+
defaultvalue: member.defaultvalue,
|
|
188
|
+
isStatic: isStatic,
|
|
189
|
+
hasGetter: false,
|
|
190
|
+
hasSetter: false,
|
|
191
|
+
getterDescription: '',
|
|
192
|
+
setterDescription: ''
|
|
165
193
|
};
|
|
166
|
-
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Check if this is a getter or setter based on description or other indicators
|
|
197
|
+
var desc = (member.description || '').toLowerCase();
|
|
198
|
+
if (desc.indexOf('获取') === 0 || desc.indexOf('get') === 0) {
|
|
199
|
+
targetObj[propName].hasGetter = true;
|
|
200
|
+
targetObj[propName].getterDescription = member.description || '';
|
|
201
|
+
} else if (desc.indexOf('设置') === 0 || desc.indexOf('set') === 0) {
|
|
202
|
+
targetObj[propName].hasSetter = true;
|
|
203
|
+
targetObj[propName].setterDescription = member.description || '';
|
|
204
|
+
} else {
|
|
205
|
+
// Regular property, use the description as is
|
|
206
|
+
if (!targetObj[propName].description) {
|
|
207
|
+
targetObj[propName].description = member.description || '';
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// Convert objects to arrays
|
|
213
|
+
var staticPropsArray = Object.keys(staticProperties).map(function(key) {
|
|
214
|
+
var prop = staticProperties[key];
|
|
215
|
+
// Combine getter/setter descriptions
|
|
216
|
+
if (prop.hasGetter && prop.hasSetter) {
|
|
217
|
+
prop.description = prop.getterDescription + ' / ' + prop.setterDescription;
|
|
218
|
+
prop.accessType = 'getter/setter';
|
|
219
|
+
} else if (prop.hasGetter) {
|
|
220
|
+
prop.description = prop.getterDescription;
|
|
221
|
+
prop.accessType = 'getter';
|
|
222
|
+
} else if (prop.hasSetter) {
|
|
223
|
+
prop.description = prop.setterDescription;
|
|
224
|
+
prop.accessType = 'setter';
|
|
225
|
+
} else {
|
|
226
|
+
prop.accessType = 'property';
|
|
227
|
+
}
|
|
228
|
+
return prop;
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
var instancePropsArray = Object.keys(instanceProperties).map(function(key) {
|
|
232
|
+
var prop = instanceProperties[key];
|
|
233
|
+
if (prop.hasGetter && prop.hasSetter) {
|
|
234
|
+
prop.description = prop.getterDescription + ' / ' + prop.setterDescription;
|
|
235
|
+
prop.accessType = 'getter/setter';
|
|
236
|
+
} else if (prop.hasGetter) {
|
|
237
|
+
prop.description = prop.getterDescription;
|
|
238
|
+
prop.accessType = 'getter';
|
|
239
|
+
} else if (prop.hasSetter) {
|
|
240
|
+
prop.description = prop.setterDescription;
|
|
241
|
+
prop.accessType = 'setter';
|
|
242
|
+
} else {
|
|
243
|
+
prop.accessType = 'property';
|
|
244
|
+
}
|
|
245
|
+
return prop;
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Create properties data with both static and instance properties
|
|
249
|
+
var propertiesData = {
|
|
250
|
+
staticProperties: staticPropsArray,
|
|
251
|
+
instanceProperties: instancePropsArray
|
|
167
252
|
};
|
|
168
253
|
?>
|
|
169
254
|
<h2 id="properties" class="subsection-title has-anchor"><?js= t('properties') ?></h2>
|
|
@@ -199,6 +284,24 @@
|
|
|
199
284
|
|
|
200
285
|
<?js
|
|
201
286
|
var methods = self.find({kind: 'function', memberof: isGlobalPage ? {isUndefined: true} : doc.longname, ...shouldExcludeInherited});
|
|
287
|
+
|
|
288
|
+
// Add mixin methods if this class has @mixes tags
|
|
289
|
+
if (doc.mixes && doc.mixes.length) {
|
|
290
|
+
doc.mixes.forEach(function(mixinName) {
|
|
291
|
+
var mixinMethods = self.find({kind: 'function', memberof: mixinName});
|
|
292
|
+
if (mixinMethods && mixinMethods.length) {
|
|
293
|
+
// Add inherited flag and source info to mixin methods
|
|
294
|
+
mixinMethods.forEach(function(mixinMethod) {
|
|
295
|
+
mixinMethod.inherited = true;
|
|
296
|
+
mixinMethod.inherits = mixinName;
|
|
297
|
+
mixinMethod.mixinSource = mixinName;
|
|
298
|
+
});
|
|
299
|
+
// Merge mixin methods with current class methods
|
|
300
|
+
methods = methods.concat(mixinMethods);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
202
305
|
if (methods && methods.length && methods.forEach) {
|
|
203
306
|
?>
|
|
204
307
|
<h2 id="methods" class="subsection-title has-anchor"><?js= t('methods') ?></h2>
|
package/tmpl/method.tmpl
CHANGED
|
@@ -7,13 +7,19 @@ var self = this;
|
|
|
7
7
|
// Check if this is a class with an explicit constructor
|
|
8
8
|
var hasExplicitConstructor = false;
|
|
9
9
|
if (data.kind === 'class') {
|
|
10
|
-
// Only
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
// Only show constructor if:
|
|
11
|
+
// 1. Has constructor parameters OR
|
|
12
|
+
// 2. Has constructor-specific description (different from class description) OR
|
|
13
|
+
// 3. Has constructor-specific examples/see/since AND also has params or different description
|
|
14
|
+
|
|
15
|
+
var hasConstructorParams = data.params && data.params.length > 0;
|
|
16
|
+
var hasConstructorSpecificDescription = data.description &&
|
|
17
|
+
data.description !== data.classdesc &&
|
|
18
|
+
data.description.trim() !== '';
|
|
19
|
+
|
|
20
|
+
// For MixIn classes and similar patterns, avoid showing constructor
|
|
21
|
+
// unless there are clear constructor-specific elements
|
|
22
|
+
hasExplicitConstructor = hasConstructorParams || hasConstructorSpecificDescription;
|
|
17
23
|
}
|
|
18
24
|
?>
|
|
19
25
|
<?js if (data.kind !== 'module' && !data.hideconstructor) { ?>
|
package/tmpl/properties.tmpl
CHANGED
|
@@ -1,109 +1,132 @@
|
|
|
1
1
|
<?js
|
|
2
2
|
var data = obj;
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
var
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
3
|
+
var self = this;
|
|
4
|
+
|
|
5
|
+
// Handle both old format (single properties array) and new format (static/instance separation)
|
|
6
|
+
var staticProps = data.staticProperties || [];
|
|
7
|
+
var instanceProps = data.instanceProperties || data.properties || [];
|
|
8
|
+
|
|
9
|
+
// Function to render a properties table
|
|
10
|
+
function renderPropertiesTable(props, title) {
|
|
11
|
+
if (!props || props.length === 0) return '';
|
|
12
|
+
|
|
13
|
+
/* sort subprops under their parent props (like opts.classname) */
|
|
14
|
+
var parentProp = null;
|
|
15
|
+
props.forEach(function(prop, i) {
|
|
16
|
+
if (!prop) { return; }
|
|
17
|
+
if ( parentProp && prop.name && prop.name.indexOf(parentProp.name + '.') === 0 ) {
|
|
18
|
+
prop.name = prop.name.substr(parentProp.name.length+1);
|
|
19
|
+
parentProp.subprops = parentProp.subprops || [];
|
|
20
|
+
parentProp.subprops.push(prop);
|
|
21
|
+
props[i] = null;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
parentProp = prop;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/* determine if we need extra columns, "attributes" and "default" */
|
|
29
|
+
props.hasAttributes = false;
|
|
30
|
+
props.hasDefault = false;
|
|
31
|
+
props.hasName = false;
|
|
32
|
+
|
|
33
|
+
props.forEach(function(prop) {
|
|
34
|
+
if (!prop) { return; }
|
|
35
|
+
|
|
36
|
+
if (prop.optional || prop.nullable) {
|
|
37
|
+
props.hasAttributes = true;
|
|
38
|
+
}
|
|
19
39
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
props.hasName = false;
|
|
40
|
+
if (prop.name) {
|
|
41
|
+
props.hasName = true;
|
|
42
|
+
}
|
|
24
43
|
|
|
25
|
-
|
|
26
|
-
|
|
44
|
+
if (typeof prop.defaultvalue !== 'undefined' && !data.isEnum) {
|
|
45
|
+
props.hasDefault = true;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
27
48
|
|
|
28
|
-
|
|
29
|
-
|
|
49
|
+
var html = '';
|
|
50
|
+
if (title) {
|
|
51
|
+
html += '<h3 class="subsection-title">' + title + '</h3>';
|
|
30
52
|
}
|
|
31
53
|
|
|
32
|
-
|
|
33
|
-
|
|
54
|
+
html += '<div class="allow-overflow">';
|
|
55
|
+
html += '<table class="props">';
|
|
56
|
+
html += '<thead><tr>';
|
|
57
|
+
|
|
58
|
+
if (props.hasName) {
|
|
59
|
+
html += '<th>' + t('name') + '</th>';
|
|
34
60
|
}
|
|
61
|
+
html += '<th>' + t('type') + '</th>';
|
|
35
62
|
|
|
36
|
-
if (
|
|
37
|
-
|
|
63
|
+
if (props.hasAttributes) {
|
|
64
|
+
html += '<th>' + t('attributes') + '</th>';
|
|
38
65
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
<?js } ?>
|
|
48
|
-
|
|
49
|
-
<th><?js= t('type') ?></th>
|
|
50
|
-
|
|
51
|
-
<?js if (props.hasAttributes) {?>
|
|
52
|
-
<th><?js= t('attributes') ?></th>
|
|
53
|
-
<?js } ?>
|
|
54
|
-
|
|
55
|
-
<?js if (props.hasDefault) {?>
|
|
56
|
-
<th><?js= t('default') ?></th>
|
|
57
|
-
<?js } ?>
|
|
58
|
-
|
|
59
|
-
<th class="last"><?js= t('description') ?></th>
|
|
60
|
-
</tr>
|
|
61
|
-
</thead>
|
|
62
|
-
|
|
63
|
-
<tbody>
|
|
64
|
-
<?js
|
|
65
|
-
var self = this;
|
|
66
|
+
|
|
67
|
+
if (props.hasDefault) {
|
|
68
|
+
html += '<th>' + t('default') + '</th>';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
html += '<th class="last">' + t('description') + '</th>';
|
|
72
|
+
html += '</tr></thead><tbody>';
|
|
73
|
+
|
|
66
74
|
props.forEach(function(prop) {
|
|
67
75
|
if (!prop) { return; }
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
</
|
|
109
|
-
|
|
76
|
+
|
|
77
|
+
html += '<tr>';
|
|
78
|
+
|
|
79
|
+
if (props.hasName) {
|
|
80
|
+
var nameDisplay = prop.name;
|
|
81
|
+
if (prop.accessType && prop.accessType !== 'property') {
|
|
82
|
+
nameDisplay += ' <em>(' + prop.accessType + ')</em>';
|
|
83
|
+
}
|
|
84
|
+
html += '<td class="name"><code>' + nameDisplay + '</code></td>';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
html += '<td class="type">';
|
|
88
|
+
if (prop.type && prop.type.names) {
|
|
89
|
+
html += self.partial('type.tmpl', prop.type.names);
|
|
90
|
+
}
|
|
91
|
+
html += '</td>';
|
|
92
|
+
|
|
93
|
+
if (props.hasAttributes) {
|
|
94
|
+
html += '<td class="attributes">';
|
|
95
|
+
if (prop.optional) {
|
|
96
|
+
html += '<optional><br>';
|
|
97
|
+
}
|
|
98
|
+
if (prop.nullable) {
|
|
99
|
+
html += '<nullable><br>';
|
|
100
|
+
}
|
|
101
|
+
html += '</td>';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (props.hasDefault) {
|
|
105
|
+
html += '<td class="default">';
|
|
106
|
+
if (typeof prop.defaultvalue !== 'undefined') {
|
|
107
|
+
html += self.htmlsafe(prop.defaultvalue);
|
|
108
|
+
}
|
|
109
|
+
html += '</td>';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
html += '<td class="description last">' + (prop.description || '');
|
|
113
|
+
if (prop.subprops) {
|
|
114
|
+
html += '<h6>Properties</h6>' + self.partial('properties.tmpl', prop);
|
|
115
|
+
}
|
|
116
|
+
html += '</td>';
|
|
117
|
+
|
|
118
|
+
html += '</tr>';
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
html += '</tbody></table></div>';
|
|
122
|
+
return html;
|
|
123
|
+
}
|
|
124
|
+
?>
|
|
125
|
+
|
|
126
|
+
<?js if (staticProps.length > 0) { ?>
|
|
127
|
+
<?js= renderPropertiesTable(staticProps, '静态属性') ?>
|
|
128
|
+
<?js } ?>
|
|
129
|
+
|
|
130
|
+
<?js if (instanceProps.length > 0) { ?>
|
|
131
|
+
<?js= renderPropertiesTable(instanceProps, staticProps.length > 0 ? '实例属性' : null) ?>
|
|
132
|
+
<?js } ?>
|