umberto 3.1.0 → 3.2.1
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/CHANGELOG.md +1596 -0
- package/README.md +6 -6
- package/package.json +5 -34
- package/src/api-builder/classes/doc-data-factory.js +37 -24
- package/src/data-converter/converters/typedoc/abstractparser.js +11 -0
- package/src/data-converter/converters/typedoc/computedpropertyparser.js +30 -0
- package/src/data-converter/converters/typedoc/typedocconverter.js +58 -14
- package/src/data-converter/converters/typedoc2umberto.js +2 -0
- package/src/hexo-manager.js +10 -1
- package/themes/umberto/layout/_api-docs/_mixin/_params.pug +10 -1
- package/themes/umberto/layout/_api-docs/_partial/api-subheader.pug +3 -0
- package/themes/umberto/layout/_api-docs/api-base.pug +0 -2
- package/themes/umberto/layout/_mixin/nav-tree-level.pug +1 -1
- package/themes/umberto/layout/_partial/nav-tree.pug +1 -1
- package/themes/umberto/src/css/_api-subheader.scss +2 -0
- package/themes/umberto/src/css/_badge.scss +1 -0
- package/themes/umberto/src/css/_tree.scss +9 -0
- package/themes/umberto/src/js/_apitree.js +12 -20
- package/themes/umberto/src/js/_sidenavigation.js +45 -4
- package/themes/umberto/src/js/app.js +3 -3
- package/.editorconfig +0 -12
- package/.eslintrc.js +0 -41
- package/scripts-dev/postinstall.js +0 -18
- package/themes/umberto/layout/_api-docs/_partial/types.pug +0 -5
package/README.md
CHANGED
|
@@ -297,6 +297,10 @@ Use `category: none` for pages not belonging to any category, e.g. 404 page. 404
|
|
|
297
297
|
|
|
298
298
|
If no `<h1>` heading is present in a guide, the title will be used to create the guide title automatically. It is recommended to put a `<h1>` heading in a guide and skip this option.
|
|
299
299
|
|
|
300
|
+
#### folded [optional]
|
|
301
|
+
|
|
302
|
+
If defined and set to `true`, the category will be folded.
|
|
303
|
+
|
|
300
304
|
#### slug [optional]
|
|
301
305
|
|
|
302
306
|
If `slug` is defined, the guide's file name after processing by Umberto will be changed to the slug.
|
|
@@ -701,15 +705,11 @@ After generating the changelog, you are able to release the package.
|
|
|
701
705
|
First, you need to bump the version:
|
|
702
706
|
|
|
703
707
|
```bash
|
|
704
|
-
npm run release:
|
|
708
|
+
npm run release:prepare-packages
|
|
705
709
|
```
|
|
706
710
|
|
|
707
|
-
You can also use the `--dry-run` option in order to see what this task does.
|
|
708
|
-
|
|
709
711
|
After bumping the version, you can publish the changes:
|
|
710
712
|
|
|
711
713
|
```bash
|
|
712
|
-
npm run release:publish
|
|
714
|
+
npm run release:publish-packages
|
|
713
715
|
```
|
|
714
|
-
|
|
715
|
-
As in the previous task, the `--dry-run` option is also available.
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "umberto",
|
|
3
|
-
"version": "3.1
|
|
3
|
+
"version": "3.2.1",
|
|
4
4
|
"description": "CKSource Documentation builder",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
7
7
|
"scripts",
|
|
8
8
|
"src",
|
|
9
9
|
"themes",
|
|
10
|
-
".editorconfig",
|
|
11
|
-
".eslintrc.js",
|
|
12
10
|
"hexo-config.json",
|
|
13
11
|
"hexo-shim.js",
|
|
14
|
-
"
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE.md",
|
|
14
|
+
"CHANGELOG.md"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@babel/core": "^7.18.10",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"escape-string-regexp": "^4.0.0",
|
|
28
28
|
"fs-extra": "^10.1.0",
|
|
29
29
|
"fuse.js": "^6.6.2",
|
|
30
|
+
"glob": "^7.2.3",
|
|
30
31
|
"hexo": "^6.2.0",
|
|
31
32
|
"hexo-generator-archive": "^1.0.0",
|
|
32
33
|
"hexo-generator-category": "^1.0.0",
|
|
@@ -55,40 +56,10 @@
|
|
|
55
56
|
"vnu-jar": "^21.10.12",
|
|
56
57
|
"webpack": "^5.74.0"
|
|
57
58
|
},
|
|
58
|
-
"devDependencies": {
|
|
59
|
-
"@ckeditor/ckeditor5-dev-bump-year": "^37.0.0",
|
|
60
|
-
"@ckeditor/ckeditor5-dev-ci": "^37.0.0",
|
|
61
|
-
"@ckeditor/ckeditor5-dev-docs": "^37.0.0",
|
|
62
|
-
"@ckeditor/ckeditor5-dev-release-tools": "^37.0.0",
|
|
63
|
-
"browser-sync": "^2.27.10",
|
|
64
|
-
"chai": "^4.3.6",
|
|
65
|
-
"chokidar": "^3.5.3",
|
|
66
|
-
"eslint": "^8.21.0",
|
|
67
|
-
"eslint-config-ckeditor5": "^4.0.1",
|
|
68
|
-
"husky": "^8.0.2",
|
|
69
|
-
"lint-staged": "^13.0.3",
|
|
70
|
-
"mocha": "^10.0.0",
|
|
71
|
-
"mockery": "^2.1.0",
|
|
72
|
-
"proxyquire": "^2.1.3",
|
|
73
|
-
"sinon": "^14.0.0",
|
|
74
|
-
"typescript": "^4.8.4"
|
|
75
|
-
},
|
|
76
59
|
"engines": {
|
|
77
60
|
"node": ">=16.0.0",
|
|
78
61
|
"npm": ">=5.7.1"
|
|
79
62
|
},
|
|
80
|
-
"scripts": {
|
|
81
|
-
"postinstall": "node ./scripts-dev/postinstall.js",
|
|
82
|
-
"dev:build-single": "node ./scripts-dev/build-single.js",
|
|
83
|
-
"dev:build-multi": "node ./scripts-dev/build-multi.js",
|
|
84
|
-
"dev:serve": "node ./scripts-dev/serve.js",
|
|
85
|
-
"lint": "eslint --quiet '**/*.js'",
|
|
86
|
-
"test": "mocha tests --recursive",
|
|
87
|
-
"coverage": "nyc --reporter=lcov --reporter=text-summary --cache false npm run test",
|
|
88
|
-
"changelog": "node ./scripts-dev/changelog.js",
|
|
89
|
-
"release:bump-version": "node ./scripts-dev/bump-version.js",
|
|
90
|
-
"release:publish": "node ./scripts-dev/publish.js"
|
|
91
|
-
},
|
|
92
63
|
"author": "CKSource (http://cksource.com/)",
|
|
93
64
|
"license": "MIT",
|
|
94
65
|
"homepage": "https://github.com/cksource/umberto",
|
|
@@ -192,16 +192,23 @@ module.exports = class DocDataFactory {
|
|
|
192
192
|
// "member-" as a static string must be the same as defined in `addTypedefProperties()` helper in the `@ckeditor/jsdoc-plugins` package.
|
|
193
193
|
// See: https://github.com/ckeditor/ckeditor5-dev/blob/aa905a702d337db001445efc1036ab2b33069d44/packages/jsdoc-plugins/lib/relation-fixer/addtypedefproperties.js#L95
|
|
194
194
|
/* eslint-enable max-len */
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
property.id
|
|
198
|
-
|
|
195
|
+
if ( doclet.kind == 'typedef' ) {
|
|
196
|
+
for ( const property of properties ) {
|
|
197
|
+
if ( !property.id ) {
|
|
198
|
+
property.id = 'member-' + property.name;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if ( !property.longname ) {
|
|
202
|
+
const [ name ] = property.id.split( 'member-' ).filter( Boolean );
|
|
203
|
+
|
|
204
|
+
property.longname = `${ doclet.longname }#${ name }`;
|
|
205
|
+
}
|
|
199
206
|
}
|
|
200
207
|
}
|
|
201
208
|
|
|
202
209
|
const itemData = {
|
|
203
210
|
types: getTypes( doclet ),
|
|
204
|
-
properties: properties.sort( ( a, b ) => a.name
|
|
211
|
+
properties: properties.sort( ( a, b ) => sorter( a.name, b.name ) ),
|
|
205
212
|
augments: augmentsNested
|
|
206
213
|
};
|
|
207
214
|
|
|
@@ -564,7 +571,15 @@ module.exports = class DocDataFactory {
|
|
|
564
571
|
}
|
|
565
572
|
|
|
566
573
|
subParams.forEach( ( sub, index ) => {
|
|
567
|
-
|
|
574
|
+
const isComputedProperty = sub.id === 'member-__index';
|
|
575
|
+
|
|
576
|
+
if ( isComputedProperty ) {
|
|
577
|
+
const [ parentParam, nestedParam ] = sub.name.split( '.' );
|
|
578
|
+
|
|
579
|
+
parent.subParamsString += `${ parentParam }<i>${ nestedParam }</i>`;
|
|
580
|
+
} else {
|
|
581
|
+
parent.subParamsString += sub.optional ? `[${ sub.name }]` : sub.name;
|
|
582
|
+
}
|
|
568
583
|
|
|
569
584
|
if ( index < subParams.length - 1 ) {
|
|
570
585
|
parent.subParamsString += ', ';
|
|
@@ -724,15 +739,7 @@ function sortLongnamesAlphabetically( arr ) {
|
|
|
724
739
|
split: splitLongname( item ).name
|
|
725
740
|
};
|
|
726
741
|
} )
|
|
727
|
-
.sort( ( a, b ) =>
|
|
728
|
-
if ( a.split < b.split ) {
|
|
729
|
-
return -1;
|
|
730
|
-
} else if ( a.split > b.split ) {
|
|
731
|
-
return 1;
|
|
732
|
-
} else {
|
|
733
|
-
return 0;
|
|
734
|
-
}
|
|
735
|
-
} )
|
|
742
|
+
.sort( ( a, b ) => sorter( a.split, b.split ) )
|
|
736
743
|
.map( item => item.entry );
|
|
737
744
|
}
|
|
738
745
|
|
|
@@ -746,15 +753,7 @@ function sortPartsAlphabetically( arr, criteria = [ {} ] ) {
|
|
|
746
753
|
for ( const crit of criteria ) {
|
|
747
754
|
const tmp = arr
|
|
748
755
|
.filter( item => item[ crit.key ] === crit.value )
|
|
749
|
-
.sort( ( a, b ) =>
|
|
750
|
-
if ( a.name < b.name ) {
|
|
751
|
-
return -1;
|
|
752
|
-
} else if ( a.name > b.name ) {
|
|
753
|
-
return 1;
|
|
754
|
-
} else {
|
|
755
|
-
return 0;
|
|
756
|
-
}
|
|
757
|
-
} );
|
|
756
|
+
.sort( ( a, b ) => sorter( a.name, b.name ) );
|
|
758
757
|
|
|
759
758
|
tmp.forEach( item => {
|
|
760
759
|
const index = arr.indexOf( item );
|
|
@@ -767,6 +766,20 @@ function sortPartsAlphabetically( arr, criteria = [ {} ] ) {
|
|
|
767
766
|
return result;
|
|
768
767
|
}
|
|
769
768
|
|
|
769
|
+
function sorter( a, b ) {
|
|
770
|
+
// Computed property name starts with the "[" character. We want to show them on the top, so let's prepend the name
|
|
771
|
+
// (only for the sorting purposes) with a space, which ASCII code is less than any other alphanumeric character.
|
|
772
|
+
if ( a.startsWith( '[' ) ) {
|
|
773
|
+
a = ' ' + a;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
if ( b.startsWith( '[' ) ) {
|
|
777
|
+
b = ' ' + b;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
return a <= b ? -1 : 1;
|
|
781
|
+
}
|
|
782
|
+
|
|
770
783
|
/**
|
|
771
784
|
* This is a JavaScript version of the `renderInlineFunction()` pug mixin.
|
|
772
785
|
*
|
|
@@ -73,6 +73,16 @@ module.exports = class AbstractParser {
|
|
|
73
73
|
return `${ parentName }${ separator }${ item.name }`;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Prepares the name for the computed property.
|
|
78
|
+
*
|
|
79
|
+
* @param {TypedocReflection<'Index signature'>} item
|
|
80
|
+
* @returns {String}
|
|
81
|
+
*/
|
|
82
|
+
getComputedName( item ) {
|
|
83
|
+
return TypedocConverter.getComputedName( item );
|
|
84
|
+
}
|
|
85
|
+
|
|
76
86
|
/**
|
|
77
87
|
* Returns the access type for the item.
|
|
78
88
|
*
|
|
@@ -121,6 +131,7 @@ module.exports = class AbstractParser {
|
|
|
121
131
|
|
|
122
132
|
case 'Accessor':
|
|
123
133
|
case 'Property':
|
|
134
|
+
case 'Index signature':
|
|
124
135
|
return 'member';
|
|
125
136
|
|
|
126
137
|
case 'Variable':
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2017-2023, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const PropertyParser = require( './propertyparser' );
|
|
9
|
+
|
|
10
|
+
module.exports = class ComputedPropertyParser extends PropertyParser {
|
|
11
|
+
/**
|
|
12
|
+
* @param {TypedocReflectionMeta} item
|
|
13
|
+
* @returns {Boolean}
|
|
14
|
+
*/
|
|
15
|
+
canParse( item ) {
|
|
16
|
+
return item.kindString === 'Index signature';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {TypedocReflection<'Index signature'>} item
|
|
21
|
+
* @param {String} parentName
|
|
22
|
+
* @returns {Object}
|
|
23
|
+
*/
|
|
24
|
+
parse( item, parentName ) {
|
|
25
|
+
return {
|
|
26
|
+
...super.parse( item, parentName ),
|
|
27
|
+
name: this.getComputedName( item )
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
};
|
|
@@ -61,6 +61,26 @@ class TypedocConverter {
|
|
|
61
61
|
return markdown.render( value ).trim();
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Prepares the name for the computed property.
|
|
66
|
+
*
|
|
67
|
+
* @param {TypedocReflection<'Index signature'>} item
|
|
68
|
+
* @returns {String}
|
|
69
|
+
*/
|
|
70
|
+
static getComputedName( item ) {
|
|
71
|
+
if ( item.kindString !== 'Index signature' ) {
|
|
72
|
+
return item.name;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// TypeDoc is able to handle only one (the first found one) index signature.
|
|
76
|
+
// See: https://github.com/TypeStrong/typedoc/blob/af63d9e4e1/src/lib/converter/factories/index-signature.ts#L20
|
|
77
|
+
const [ firstParam ] = item.parameters;
|
|
78
|
+
const paramName = firstParam.name;
|
|
79
|
+
const paramType = firstParam.type.name;
|
|
80
|
+
|
|
81
|
+
return `[${ paramName }: ${ paramType }]`;
|
|
82
|
+
}
|
|
83
|
+
|
|
64
84
|
/**
|
|
65
85
|
* @param {Object} projectReflection
|
|
66
86
|
* @param {Array.<TypedocReflection>} projectReflection.children
|
|
@@ -177,16 +197,21 @@ class TypedocConverter {
|
|
|
177
197
|
}
|
|
178
198
|
}
|
|
179
199
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
200
|
+
// A computed property is stored in the `indexSignature` key, but we want to convert it in the same way as we do for a "normal"
|
|
201
|
+
// property. Hence, let's just treat the `indexSignature` as it would be a doclet's child, so the dedicated parser for the
|
|
202
|
+
// `indexSignature` can prepare a doclet for the computed property.
|
|
203
|
+
if ( reflection.children || reflection.indexSignature ) {
|
|
204
|
+
parentName = doclets ? doclets[ 0 ].longname : '';
|
|
205
|
+
|
|
206
|
+
if ( reflection.children ) {
|
|
207
|
+
reflection.children.forEach( subItem => {
|
|
208
|
+
this._convertChild( subItem, parentName );
|
|
209
|
+
} );
|
|
185
210
|
}
|
|
186
211
|
|
|
187
|
-
reflection.
|
|
188
|
-
this._convertChild(
|
|
189
|
-
}
|
|
212
|
+
if ( reflection.indexSignature ) {
|
|
213
|
+
this._convertChild( reflection.indexSignature, parentName );
|
|
214
|
+
}
|
|
190
215
|
}
|
|
191
216
|
}
|
|
192
217
|
|
|
@@ -243,18 +268,37 @@ class TypedocConverter {
|
|
|
243
268
|
*/
|
|
244
269
|
_convertProperties( signature ) {
|
|
245
270
|
const types = signature.type.type === 'union' ? signature.type.types : [ signature.type ];
|
|
246
|
-
const type = types.find( type => type.declaration && type.declaration.children );
|
|
247
271
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
272
|
+
const properties = types
|
|
273
|
+
.filter( type => type.declaration )
|
|
274
|
+
.flatMap( type => {
|
|
275
|
+
const result = [];
|
|
276
|
+
|
|
277
|
+
if ( type.declaration.children ) {
|
|
278
|
+
result.push( ...type.declaration.children );
|
|
279
|
+
}
|
|
251
280
|
|
|
252
|
-
|
|
281
|
+
if ( type.declaration.indexSignature ) {
|
|
282
|
+
result.push( type.declaration.indexSignature );
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return result;
|
|
286
|
+
} );
|
|
287
|
+
|
|
288
|
+
return properties.map( child => {
|
|
253
289
|
// Nested properties cannot be duplicated so we can take the first signature when processing functions.
|
|
254
290
|
const childSignature = child.kindString === 'Method' ? child.signatures[ 0 ] : child;
|
|
255
291
|
const response = this._convertTypeToJsDoc( childSignature );
|
|
256
292
|
|
|
257
|
-
|
|
293
|
+
if ( child.kindString === 'Index signature' ) {
|
|
294
|
+
// For computed property (stored as index signature by TypeDoc), explicitly create the `id` key (as `extraId` key).
|
|
295
|
+
// The `id` is then used to created the `longname` key. Otherwise, the `id` and `longname` keys would be created
|
|
296
|
+
// automatically later and they would contain computed name in their values.
|
|
297
|
+
response.extraId = `member-${ childSignature.name }`;
|
|
298
|
+
response.name = TypedocConverter.getComputedName( childSignature );
|
|
299
|
+
} else {
|
|
300
|
+
response.name = childSignature.name;
|
|
301
|
+
}
|
|
258
302
|
|
|
259
303
|
if ( signature.comment && signature.comment.blockTags ) {
|
|
260
304
|
const atProperty = signature.comment.blockTags.find( blockTag => {
|
|
@@ -14,6 +14,7 @@ const ConstantParser = require( './typedoc/constantparser' );
|
|
|
14
14
|
const TypeParser = require( './typedoc/typeparser' );
|
|
15
15
|
const FunctionParser = require( './typedoc/functionparser' );
|
|
16
16
|
const PropertyParser = require( './typedoc/propertyparser' );
|
|
17
|
+
const ComputedPropertyParser = require( './typedoc/computedpropertyparser' );
|
|
17
18
|
const MethodParser = require( './typedoc/methodparser' );
|
|
18
19
|
const ConstructorParser = require( './typedoc/constructorparser' );
|
|
19
20
|
const ErrorParser = require( './typedoc/errorparser' );
|
|
@@ -45,6 +46,7 @@ module.exports = data => {
|
|
|
45
46
|
MethodParser,
|
|
46
47
|
AccessorParser,
|
|
47
48
|
PropertyParser,
|
|
49
|
+
ComputedPropertyParser,
|
|
48
50
|
EventParser
|
|
49
51
|
] );
|
|
50
52
|
|
package/src/hexo-manager.js
CHANGED
|
@@ -85,7 +85,16 @@ class HexoManager {
|
|
|
85
85
|
hexoInit() {
|
|
86
86
|
this.isReady = true;
|
|
87
87
|
|
|
88
|
-
return this.hexo.init()
|
|
88
|
+
return this.hexo.init().then( () => {
|
|
89
|
+
const renderer = this.hexo.render.renderer.get( 'md' );
|
|
90
|
+
|
|
91
|
+
// Disable Nunjucks templating language in the Markdown renderer.
|
|
92
|
+
// See https://github.com/ckeditor/ckeditor5/issues/14189.
|
|
93
|
+
if ( renderer ) {
|
|
94
|
+
renderer.disableNunjucks = true;
|
|
95
|
+
this.hexo.extend.renderer.register( 'md', 'html', renderer );
|
|
96
|
+
}
|
|
97
|
+
} );
|
|
89
98
|
}
|
|
90
99
|
|
|
91
100
|
/**
|
|
@@ -10,12 +10,21 @@ mixin paramsMixin ( params, level, title )
|
|
|
10
10
|
|
|
11
11
|
dl
|
|
12
12
|
each param in params
|
|
13
|
+
- const isComputedProperty = param.id === 'member-__index';
|
|
14
|
+
|
|
13
15
|
dt
|
|
14
16
|
code
|
|
15
|
-
if
|
|
17
|
+
if isComputedProperty
|
|
18
|
+
- const [ parentParam, nestedParam ] = param.name.split( '.' );
|
|
19
|
+
|
|
20
|
+
| #{ parentParam }
|
|
21
|
+
i
|
|
22
|
+
| #{ nestedParam }
|
|
23
|
+
else if param.optional
|
|
16
24
|
| [ #{ param.name } ]
|
|
17
25
|
else
|
|
18
26
|
| #{ param.name }
|
|
27
|
+
|
|
19
28
|
if isNonEmptyArray( param.types )
|
|
20
29
|
| :
|
|
21
30
|
| !{ ' ' }
|
|
@@ -6,6 +6,9 @@ div(class="api-subheader hidden-loading")
|
|
|
6
6
|
if isNonEmptyArray( data.badges )
|
|
7
7
|
each badge in data.badges
|
|
8
8
|
+badge( badge )
|
|
9
|
+
if isNonEmptyArray( data.types )
|
|
10
|
+
code
|
|
11
|
+
+type( data.types )
|
|
9
12
|
nav.api-subheader__navigation
|
|
10
13
|
if ( isNonEmptyArray( data.configOptions ) || isNonEmptyArray( data.properties ) || isNonEmptyArray( data.methods ) || isNonEmptyArray( data.events ) )
|
|
11
14
|
ul
|
|
@@ -29,7 +29,7 @@ mixin navTreeLevel( data, isRoot )
|
|
|
29
29
|
each badge in normalizeBadges( data )
|
|
30
30
|
span( class="tree__item__badge tree__item__badge_" + badge.name data-badge-tooltip=badge.label )
|
|
31
31
|
span( class="tree__item__badge__text" ) #{ badge.label }
|
|
32
|
-
ul
|
|
32
|
+
ul( class={ "tree__item-nested-list": true, "tree__item-nested-list--hidden": data.folded } data-id=data.id )
|
|
33
33
|
each item in dataArr
|
|
34
34
|
//- Categories have a property 'name', guides don't have property 'name'.
|
|
35
35
|
if item.name
|
|
@@ -24,6 +24,15 @@ See: `_api-tree.scss` and `_guide-sdk-tree.scss`. */
|
|
|
24
24
|
|
|
25
25
|
list-style: none;
|
|
26
26
|
|
|
27
|
+
&.guide-tree {
|
|
28
|
+
opacity: 0; //prevents flickering when applying categories fold state
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&.state-applied {
|
|
32
|
+
opacity: 1;
|
|
33
|
+
transition: opacity 0.05s
|
|
34
|
+
}
|
|
35
|
+
|
|
27
36
|
li {
|
|
28
37
|
position: relative;
|
|
29
38
|
cursor: pointer;
|
|
@@ -42,31 +42,23 @@ export function scrollApiTree() {
|
|
|
42
42
|
const treeHeight = tree.height();
|
|
43
43
|
const storageKey = 'side-nav-scroll-top';
|
|
44
44
|
const sideNavScrollTop = Number( window.localStorage.getItem( storageKey ) );
|
|
45
|
-
const treeItemClass = 'tree__item__wrapper';
|
|
46
45
|
const activeTreeItemClass = 'tree__item__wrapper--active';
|
|
47
46
|
const activeTreeItem = $( `div.side-navigation .${ activeTreeItemClass }` );
|
|
48
|
-
|
|
49
|
-
const activeTreeItemIndex = treeWrappers.index( activeTreeItem );
|
|
50
|
-
let activeTreeItemTop = 25; // 25 is for top padding of side nav.
|
|
47
|
+
let activeTreeItemTop = 0;
|
|
51
48
|
const bound = 50; // Offset from top and bottom of side nav.
|
|
52
49
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if ( activeTreeItemIndex === -1 || index === activeTreeItemIndex ) {
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
activeTreeItemTop += $( this ).height();
|
|
60
|
-
} );
|
|
50
|
+
if ( activeTreeItem.length ) {
|
|
51
|
+
activeTreeItemTop = activeTreeItem[ 0 ].offsetParent ? activeTreeItem[ 0 ].offsetParent.offsetTop : 0;
|
|
61
52
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
53
|
+
if (
|
|
54
|
+
sideNavScrollTop !== null &&
|
|
55
|
+
activeTreeItemTop > sideNavScrollTop + bound &&
|
|
56
|
+
activeTreeItemTop < sideNavScrollTop + treeHeight - bound
|
|
57
|
+
) {
|
|
58
|
+
tree.scrollTop( sideNavScrollTop );
|
|
59
|
+
} else {
|
|
60
|
+
activeTreeItem[ 0 ].scrollIntoView( { block: 'center' } );
|
|
61
|
+
}
|
|
70
62
|
}
|
|
71
63
|
|
|
72
64
|
tree.scroll( throttle( () => {
|
|
@@ -5,14 +5,55 @@
|
|
|
5
5
|
|
|
6
6
|
export default function sideNavigation() {
|
|
7
7
|
const folderButtons = Array.from( document.querySelectorAll( '.tree:not(.api-tree) .tree__item--folder' ) );
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const guideTreeElement = document.getElementById( 'guidetree' );
|
|
9
|
+
const foldedClassName = 'tree__item-nested-list--hidden';
|
|
10
|
+
const activeClassName = '.tree__item__wrapper--active';
|
|
11
|
+
const localStorageKey = 'foldersState';
|
|
12
|
+
|
|
13
|
+
let foldersState = JSON.parse( window.localStorage.getItem( localStorageKey ) );
|
|
14
|
+
if ( foldersState === null ) {
|
|
15
|
+
foldersState = {};
|
|
10
16
|
}
|
|
11
17
|
|
|
12
18
|
folderButtons.forEach( btn => {
|
|
19
|
+
const element = btn.parentNode.nextElementSibling; // Get <ul> element
|
|
20
|
+
const id = element.getAttribute( 'data-id' );
|
|
21
|
+
|
|
22
|
+
applyFolderState( element, foldersState[ id ] );
|
|
23
|
+
checkForActiveChildren( element, id );
|
|
24
|
+
|
|
13
25
|
btn.addEventListener( 'click', function() {
|
|
14
|
-
|
|
15
|
-
|
|
26
|
+
element.classList.toggle( foldedClassName );
|
|
27
|
+
saveFolderState( id, isFolded( element ) );
|
|
16
28
|
} );
|
|
17
29
|
} );
|
|
30
|
+
|
|
31
|
+
if ( guideTreeElement ) {
|
|
32
|
+
guideTreeElement.classList.add( 'state-applied' );
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function applyFolderState( element, folded ) {
|
|
36
|
+
if ( folded === false ) {
|
|
37
|
+
element.classList.remove( foldedClassName );
|
|
38
|
+
}
|
|
39
|
+
if ( folded === true ) {
|
|
40
|
+
element.classList.add( foldedClassName );
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function saveFolderState( id, state ) {
|
|
45
|
+
foldersState[ id ] = state;
|
|
46
|
+
window.localStorage.setItem( localStorageKey, JSON.stringify( foldersState ) );
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function checkForActiveChildren( element, id ) {
|
|
50
|
+
if ( element.querySelectorAll( activeClassName ).length > 0 ) {
|
|
51
|
+
element.classList.remove( foldedClassName );
|
|
52
|
+
saveFolderState( id, isFolded( element ) );
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isFolded( element ) {
|
|
57
|
+
return element.classList.contains( foldedClassName );
|
|
58
|
+
}
|
|
18
59
|
}
|
|
@@ -44,19 +44,19 @@ window.umberto = {
|
|
|
44
44
|
$( document ).ready( () => {
|
|
45
45
|
pageNavigation(); // pageNavigation - needs to be run before filtering initialization.
|
|
46
46
|
copyMobileApiNavigation(); // copy API Tree into mobile navigation
|
|
47
|
+
sideNavigation();
|
|
48
|
+
expandApiTree();
|
|
49
|
+
scrollApiTree();
|
|
47
50
|
enableFiltering();
|
|
48
51
|
setupPrism();
|
|
49
|
-
expandApiTree();
|
|
50
52
|
enableCollapsables();
|
|
51
53
|
hideTogglers();
|
|
52
54
|
enableAnchors();
|
|
53
55
|
enableDropdowns();
|
|
54
56
|
trackArticlePosition();
|
|
55
|
-
scrollApiTree();
|
|
56
57
|
setUpFuse();
|
|
57
58
|
activateDevNames();
|
|
58
59
|
attachPermalinkListener();
|
|
59
|
-
sideNavigation();
|
|
60
60
|
rwdButton();
|
|
61
61
|
imageModal(); // lightbox for { @img } elements
|
|
62
62
|
// `sampleCode()` must be called after the `setupPrism()` function.
|
package/.editorconfig
DELETED