umberto 9.1.2 → 9.1.3
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 +11 -15
- package/package.json +1 -1
- package/scripts/filter/after-post-render/time-end.js +1 -1
- package/scripts/filter/before-post-render/gloria/prerender-xml-pug-components.js +1 -1
- package/scripts/utils/execute-and-insert-function-results.js +1 -1
- package/scripts/utils/has-own-favicons.js +1 -1
- package/scripts/utils/inline-svg.js +2 -2
- package/scripts/utils/logcrossprojectreference.js +1 -1
- package/scripts/utils/parseicontag.js +1 -1
- package/scripts/utils/parselinks.js +1 -1
- package/scripts/utils/pug-renderer/render-pug-component.js +1 -1
- package/scripts/utils/random-id.js +1 -1
- package/scripts/utils/spritesheet-svg.js +2 -2
- package/scripts/utils/toc.js +46 -6
- package/src/api-builder/build-page-worker.js +1 -1
- package/src/api-builder/classes/description-parser.js +1 -1
- package/src/helpers/get-docsearch-config.js +1 -1
- package/src/helpers/github-url.js +1 -1
- package/src/helpers/import-module.js +1 -1
- package/src/helpers/log-with-time.js +1 -1
- package/src/hexo-manager.js +1 -1
- package/src/index.js +2 -2
- package/src/sdk-builder/get-sdk-sources.js +1 -1
- package/src/sdk-builder/sdk-builder.js +1 -1
- package/src/tasks/create-sitemap-index.js +1 -1
- package/src/tasks/create-sitemap-step.js +1 -1
- package/src/tasks/create-sitemap.js +2 -2
- package/src/tasks/create-sym-links.js +2 -2
- package/src/tasks/get-hexo-config.js +1 -1
- package/src/tasks/get-main-config.js +1 -1
- package/src/tasks/get-project-config.js +1 -1
- package/src/tasks/minify-html-worker.js +1 -1
- package/src/tasks/minify-html.js +3 -3
- package/src/tasks/read-doc-sources.js +1 -1
- package/src/tasks/run-webpack.js +1 -1
- package/src/tasks/validate-html-w3c.js +1 -1
- package/src/tasks/validate-links.js +1 -1
- package/src/tasks/watcher.js +1 -1
- package/src/template/template-collection.js +1 -1
- package/themes/umberto/layout/gloria/_modules/sentry/index.pug +7 -1
- package/themes/umberto/layout/gloria/_modules/toc/_style.scss +10 -1
- package/themes/umberto/src/gloria/js/modules/algolia-search.js +45 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
## [9.1.3](https://github.com/cksource/umberto/compare/v9.1.2...v9.1.3) (December 19, 2025)
|
|
5
|
+
|
|
6
|
+
### Bug fixes
|
|
7
|
+
|
|
8
|
+
* Fixed the conflict where typing the forward slash in the Kapa widget would trigger the Algolia search.
|
|
9
|
+
|
|
10
|
+
### Other changes
|
|
11
|
+
|
|
12
|
+
* Added CKBox (`CKBOX_VERSION`) and CKEditor 5 (`CKEDITOR_VERSION`) versions to events sent to Sentry integration.
|
|
13
|
+
|
|
14
|
+
|
|
4
15
|
## [9.1.2](https://github.com/cksource/umberto/compare/v9.1.1...v9.1.2) (December 8, 2025)
|
|
5
16
|
|
|
6
17
|
### Bug fixes
|
|
@@ -37,21 +48,6 @@ Changelog
|
|
|
37
48
|
|
|
38
49
|
* Updated the required version of Node.js to **v24.11**.
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
## [8.4.0](https://github.com/cksource/umberto/compare/v8.3.5...v8.4.0) (October 30, 2025)
|
|
42
|
-
|
|
43
|
-
### Features
|
|
44
|
-
|
|
45
|
-
* Minify output HTML to reduce file size and improve load performance.
|
|
46
|
-
|
|
47
|
-
The output is automatically minified during production builds to remove unnecessary whitespace and comments.
|
|
48
|
-
|
|
49
|
-
Minification is **disabled when using the `--dev` modifier**, ensuring the generated HTML remains readable for easier debugging and inspection.
|
|
50
|
-
|
|
51
|
-
### Other changes
|
|
52
|
-
|
|
53
|
-
* Umberto reads a project configuration once and passes it through the pipeline. Thanks to that, hooks can modify it, which affects a project's build.
|
|
54
|
-
|
|
55
51
|
---
|
|
56
52
|
|
|
57
53
|
To see all releases, visit the [release page](https://github.com/cksource/umberto/releases).
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
const { format, styleText } = require( 'util' );
|
|
8
|
+
const { format, styleText } = require( 'node:util' );
|
|
9
9
|
|
|
10
10
|
hexo.extend.filter.register( 'after_post_render', page => {
|
|
11
11
|
if ( !hexo.projectGlobals.common || !hexo.projectGlobals.common.verbose ) {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
|
|
43
43
|
'use strict';
|
|
44
44
|
|
|
45
|
-
const path = require( 'path' );
|
|
45
|
+
const path = require( 'node:path' );
|
|
46
46
|
const removeIndentation = require( '../../../utils/remove-indentation' );
|
|
47
47
|
const createPrerenderPugTemplate = require( '../../../utils/pug-renderer/create-prerender-pug-template' );
|
|
48
48
|
const {
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
const fs = require( 'fs' );
|
|
9
|
-
const path = require( 'path' );
|
|
8
|
+
const fs = require( 'node:fs' );
|
|
9
|
+
const path = require( 'node:path' );
|
|
10
10
|
const { parseDocument } = require( 'htmlparser2' );
|
|
11
11
|
const { Element, Text } = require( 'domhandler' );
|
|
12
12
|
const { selectAll, selectOne } = require( 'css-select' );
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
const fs = require( 'fs' );
|
|
9
|
-
const path = require( 'path' );
|
|
8
|
+
const fs = require( 'node:fs' );
|
|
9
|
+
const path = require( 'node:path' );
|
|
10
10
|
const { parseDocument } = require( 'htmlparser2' );
|
|
11
11
|
const { Element, cloneNode } = require( 'domhandler' );
|
|
12
12
|
const { selectAll, selectOne } = require( 'css-select' );
|
package/scripts/utils/toc.js
CHANGED
|
@@ -43,14 +43,25 @@ module.exports = function toc( data, options = {} ) {
|
|
|
43
43
|
for ( const heading of headings ) {
|
|
44
44
|
const hLevel = Number( heading.name[ 1 ] ); // 'h2' -> 2
|
|
45
45
|
const text = getHeadingText( heading ).trim();
|
|
46
|
+
const icons = getHeadingIcons( heading );
|
|
46
47
|
const li = new Element( 'li', {} );
|
|
47
|
-
const
|
|
48
|
-
class: 'a11y-focusable',
|
|
48
|
+
const aAttrs = {
|
|
49
|
+
class: icons.length > 0 ? 'a11y-focusable c-toc__link--with-icon' : 'a11y-focusable',
|
|
49
50
|
href: '#' + getAttributeValue( heading, 'id' ),
|
|
50
51
|
title: text
|
|
51
|
-
}
|
|
52
|
+
};
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
const a = new Element( 'a', aAttrs );
|
|
55
|
+
|
|
56
|
+
// Append text first, then icons (only if icons exist)
|
|
57
|
+
if ( text ) {
|
|
58
|
+
appendChild( a, new Text( text ) );
|
|
59
|
+
}
|
|
60
|
+
if ( icons.length > 0 ) {
|
|
61
|
+
for ( const icon of icons ) {
|
|
62
|
+
appendChild( a, cloneNode( icon, true ) );
|
|
63
|
+
}
|
|
64
|
+
}
|
|
54
65
|
appendChild( li, a );
|
|
55
66
|
|
|
56
67
|
if ( tocLastLevels[ hLevel ] ) {
|
|
@@ -107,7 +118,7 @@ function hasAncestorWithClassIn( node, classNames ) {
|
|
|
107
118
|
}
|
|
108
119
|
|
|
109
120
|
/**
|
|
110
|
-
* Returns the heading text without content from descendants with class "headerlink".
|
|
121
|
+
* Returns the heading text without content from descendants with class "headerlink", "editor-icon", or badge components.
|
|
111
122
|
*/
|
|
112
123
|
function getHeadingText( root ) {
|
|
113
124
|
if ( !root ) {
|
|
@@ -117,9 +128,38 @@ function getHeadingText( root ) {
|
|
|
117
128
|
// Clone so we don't mutate the original AST.
|
|
118
129
|
const clone = cloneNode( root, true );
|
|
119
130
|
|
|
120
|
-
|
|
131
|
+
// Remove headerlinks, editor-icons, and badge components (which contain icons)
|
|
132
|
+
for ( const node of selectAll( '.headerlink, .editor-icon, .c-badge', clone ) ) {
|
|
121
133
|
removeElement( node );
|
|
122
134
|
}
|
|
123
135
|
|
|
124
136
|
return textContent( clone );
|
|
125
137
|
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Returns icon elements from the heading.
|
|
141
|
+
* Looks for:
|
|
142
|
+
* - Elements with class "editor-icon" (legacy format)
|
|
143
|
+
* - Badge components with icons (c-badge with c-icon inside)
|
|
144
|
+
* - Direct icon elements (c-icon) within the heading
|
|
145
|
+
*/
|
|
146
|
+
function getHeadingIcons( root ) {
|
|
147
|
+
if ( !root ) {
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const icons = [];
|
|
152
|
+
|
|
153
|
+
const editorIcons = selectAll( '.editor-icon', root );
|
|
154
|
+
icons.push( ...editorIcons );
|
|
155
|
+
|
|
156
|
+
const badgesWithIcons = selectAll( '.c-badge .c-icon', root );
|
|
157
|
+
icons.push( ...badgesWithIcons );
|
|
158
|
+
|
|
159
|
+
const directIcons = selectAll( '.c-icon', root ).filter( icon => {
|
|
160
|
+
return !hasAncestorWithClassIn( icon, [ 'c-badge' ] );
|
|
161
|
+
} );
|
|
162
|
+
icons.push( ...directIcons );
|
|
163
|
+
|
|
164
|
+
return icons;
|
|
165
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
const { styleText } = require( 'util' );
|
|
8
|
+
const { styleText } = require( 'node:util' );
|
|
9
9
|
const { parseDocument } = require( 'htmlparser2' );
|
|
10
10
|
const { default: render } = require( 'dom-serializer' );
|
|
11
11
|
const { selectAll, selectOne } = require( 'css-select' );
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const { cloneDeep } = require( 'lodash' );
|
|
9
9
|
const { stringify } = require( 'javascript-stringify' );
|
|
10
|
-
const fs = require( 'fs' );
|
|
10
|
+
const fs = require( 'node:fs' );
|
|
11
11
|
const upath = require( 'upath' );
|
|
12
12
|
|
|
13
13
|
const defaultScriptTemplate = fs.readFileSync( upath.join( __dirname, 'templates', 'scripts', 'default.js' ), 'utf-8' );
|
package/src/hexo-manager.js
CHANGED
package/src/index.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
const { styleText } = require( 'util' );
|
|
9
|
-
const path = require( 'path' );
|
|
8
|
+
const { styleText } = require( 'node:util' );
|
|
9
|
+
const path = require( 'node:path' );
|
|
10
10
|
const compileSass = require( './tasks/compile-sass' );
|
|
11
11
|
const runWebpack = require( './tasks/run-webpack' );
|
|
12
12
|
const copyAssets = require( './tasks/copy-assets' );
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const HtmlFile = require( '../api-builder/classes/html-file' );
|
|
9
9
|
const upath = require( 'upath' );
|
|
10
|
-
const { URL, resolve: urlResolve } = require( 'url' );
|
|
10
|
+
const { URL, resolve: urlResolve } = require( 'node:url' );
|
|
11
11
|
const beautifyHtml = require( 'js-beautify' ).html;
|
|
12
12
|
const macroReplacer = require( '../tasks/macro-replacer' );
|
|
13
13
|
const getDocSearchConfig = require( '../helpers/get-docsearch-config' );
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
const fs = require( 'fs' );
|
|
8
|
+
const fs = require( 'node:fs' );
|
|
9
9
|
const { globSync } = require( 'glob' );
|
|
10
10
|
const upath = require( 'upath' );
|
|
11
|
-
const { URL } = require( 'url' );
|
|
11
|
+
const { URL } = require( 'node:url' );
|
|
12
12
|
const { SitemapStream, streamToPromise } = require( 'sitemap' );
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
const { styleText } = require( 'util' );
|
|
9
|
-
const fs = require( 'fs' );
|
|
8
|
+
const { styleText } = require( 'node:util' );
|
|
9
|
+
const fs = require( 'node:fs' );
|
|
10
10
|
const upath = require( 'upath' );
|
|
11
11
|
const getProjectConfig = require( './get-project-config' );
|
|
12
12
|
|
package/src/tasks/minify-html.js
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
const { join } = require( 'path' );
|
|
9
|
-
const { globSync } = require( 'fs' );
|
|
10
|
-
const { styleText } = require( 'util' );
|
|
8
|
+
const { join } = require( 'node:path' );
|
|
9
|
+
const { globSync } = require( 'node:fs' );
|
|
10
|
+
const { styleText } = require( 'node:util' );
|
|
11
11
|
const { default: TinyPool } = require( 'tinypool' );
|
|
12
12
|
const logWithTime = require( '../helpers/log-with-time' );
|
|
13
13
|
|
package/src/tasks/run-webpack.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* For licensing, see LICENSE.md.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
const { spawn } = require( 'child_process' );
|
|
6
|
+
const { spawn } = require( 'node:child_process' );
|
|
7
7
|
const vnu = require( 'vnu-jar' );
|
|
8
8
|
|
|
9
9
|
module.exports = ( buildPath, { verbose } = {} ) => new Promise( ( resolve, reject ) => {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* especially for API documentation where the number of links can reach thousands.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
const { styleText } = require( 'util' );
|
|
14
|
+
const { styleText } = require( 'node:util' );
|
|
15
15
|
const fs = require( 'fs-extra' );
|
|
16
16
|
const upath = require( 'upath' );
|
|
17
17
|
const { globSync } = require( 'glob' );
|
package/src/tasks/watcher.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
8
|
const pug = require( 'pug' );
|
|
9
|
-
const fs = require( 'fs' );
|
|
9
|
+
const fs = require( 'node:fs' );
|
|
10
10
|
const upath = require( 'upath' );
|
|
11
11
|
const isNonEmptyArray = require( '../helpers/is-non-empty-array' );
|
|
12
12
|
const createFilterAttribs = require( '../helpers/create-filtering-data-attribs' );
|
|
@@ -17,7 +17,13 @@ mixin load-sentry-script( sentry )
|
|
|
17
17
|
'https://ckeditor5.github.io/docs/nightly'
|
|
18
18
|
],
|
|
19
19
|
replaysSessionSampleRate: 0,
|
|
20
|
-
replaysOnErrorSampleRate: 0
|
|
20
|
+
replaysOnErrorSampleRate: 0,
|
|
21
|
+
initialScope: scope => {
|
|
22
|
+
scope.setTags( {
|
|
23
|
+
CKEDITOR_VERSION: typeof CKEDITOR_VERSION !== 'undefined' ? CKEDITOR_VERSION : '(none)',
|
|
24
|
+
CKBOX_VERSION: typeof CKBox !== 'undefined' ? CKBox.version : '(none)',
|
|
25
|
+
} );
|
|
26
|
+
}
|
|
21
27
|
} );
|
|
22
28
|
};
|
|
23
29
|
|
|
@@ -183,12 +183,21 @@
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
ol a {
|
|
186
|
-
display: block;
|
|
187
186
|
padding: 0 var(--spacing-2);
|
|
188
187
|
text-decoration: none;
|
|
189
188
|
font-size: var(--font-size-sm);
|
|
190
189
|
color: var(--color-secondary-700);
|
|
191
190
|
|
|
191
|
+
&:not(.c-toc__link--with-icon) {
|
|
192
|
+
display: block;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
&.c-toc__link--with-icon {
|
|
196
|
+
display: flex;
|
|
197
|
+
align-items: center;
|
|
198
|
+
gap: var(--spacing-1);
|
|
199
|
+
}
|
|
200
|
+
|
|
192
201
|
&:hover,
|
|
193
202
|
&.is-active {
|
|
194
203
|
color: var(--color-primary);
|
|
@@ -46,6 +46,11 @@ export class AlgoliaSearch extends BaseComponent {
|
|
|
46
46
|
* Initializes the algolia search component.
|
|
47
47
|
*/
|
|
48
48
|
async init() {
|
|
49
|
+
// IMPORTANT: Add the keyboard event interceptor BEFORE loading the DocSearch library
|
|
50
|
+
// It ensures our listener is registered first and can use `stopImmediatePropagation`
|
|
51
|
+
// to prevent DocSearch's listener from running when typing in the Kapa widget.
|
|
52
|
+
this._preventDocSearchShortcutInKapa();
|
|
53
|
+
|
|
49
54
|
await injectScript( DOCSEARCH_JS_URL, {
|
|
50
55
|
attributes: {
|
|
51
56
|
crossorigin: 'anonymous'
|
|
@@ -88,6 +93,46 @@ export class AlgoliaSearch extends BaseComponent {
|
|
|
88
93
|
}
|
|
89
94
|
} );
|
|
90
95
|
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Prevents the DocSearch "/" keyboard shortcut from triggering when the user is typing in the Kapa widget.
|
|
99
|
+
* DocSearch library doesn't provide a configuration option to disable keyboard shortcuts,
|
|
100
|
+
* so we need to intercept the event and stop it completely before DocSearch's listener sees it.
|
|
101
|
+
*
|
|
102
|
+
* This listener is added in the capture phase BEFORE DocSearch is loaded, ensuring it runs first.
|
|
103
|
+
* We use stopImmediatePropagation() to prevent ALL other listeners (including DocSearch's) from running.
|
|
104
|
+
*/
|
|
105
|
+
_preventDocSearchShortcutInKapa() {
|
|
106
|
+
document.addEventListener( 'keydown', event => {
|
|
107
|
+
// Only handle the "/" key
|
|
108
|
+
if ( event.key !== '/' ) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Use `composedPath()` to check the entire event path, including through shadow DOM boundaries.
|
|
113
|
+
// This is more reliable than checking `document.activeElement` for shadow DOM content.
|
|
114
|
+
const path = event.composedPath();
|
|
115
|
+
|
|
116
|
+
const isTypingInInput = path.some( element => {
|
|
117
|
+
if ( !element || !element.tagName ) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Let's check different types of input fields.
|
|
122
|
+
// Kapa currently uses a textarea for the search input.
|
|
123
|
+
// But there's a chance that it will change in the future.
|
|
124
|
+
const isInputElement = element.tagName === 'TEXTAREA' ||
|
|
125
|
+
element.tagName === 'INPUT' ||
|
|
126
|
+
element.isContentEditable;
|
|
127
|
+
|
|
128
|
+
return isInputElement;
|
|
129
|
+
} );
|
|
130
|
+
|
|
131
|
+
if ( isTypingInInput ) {
|
|
132
|
+
event.stopImmediatePropagation();
|
|
133
|
+
}
|
|
134
|
+
}, true );
|
|
135
|
+
}
|
|
91
136
|
}
|
|
92
137
|
|
|
93
138
|
/**
|