umberto 8.0.0 → 8.0.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +17 -7
  2. package/package.json +1 -1
  3. package/scripts/filter/after-post-render/gloria/append-copy-heading-buttons.js +17 -26
  4. package/scripts/filter/after-post-render/parseicontag.js +1 -1
  5. package/scripts/filter/after-render/gloria/inline-svg.js +1 -1
  6. package/scripts/filter/after-render/gloria/spritesheet-svg.js +1 -1
  7. package/scripts/filter/before-post-render/gloria/add-breadcrumbs-data-to-page.js +9 -2
  8. package/scripts/filter/before-post-render/gloria/prerender-xml-pug-components.js +13 -0
  9. package/scripts/filter/before-post-render/gloria/render-post-render-pug-components.js +14 -6
  10. package/scripts/helper/u-extract-and-cache-title.js +36 -0
  11. package/scripts/utils/pug-renderer/create-prerender-pug-template.js +18 -5
  12. package/scripts/utils/random-id.js +8 -0
  13. package/src/hexo/filter/project-locals.js +3 -0
  14. package/src/tasks/build-api-docs.js +1 -1
  15. package/src/tasks/build-documentation.js +13 -3
  16. package/src/tasks/validate-links.js +211 -39
  17. package/themes/umberto/layout/gloria/_api-docs/_mixin/_api-tree-item.pug +10 -2
  18. package/themes/umberto/layout/gloria/_api-docs/_toc/_style.scss +3 -1
  19. package/themes/umberto/layout/gloria/_components/code-block/_style.scss +2 -2
  20. package/themes/umberto/layout/gloria/_components/code-block/index.pug +10 -2
  21. package/themes/umberto/layout/gloria/_components/code-switcher/_style.scss +0 -5
  22. package/themes/umberto/layout/gloria/_components/code-switcher/index.pug +3 -3
  23. package/themes/umberto/layout/gloria/_components/icon-message/index.pug +5 -5
  24. package/themes/umberto/layout/gloria/_components/index.pug +1 -0
  25. package/themes/umberto/layout/gloria/_components/nav-tree/index.pug +1 -1
  26. package/themes/umberto/layout/gloria/_components/nav-tree/nav-tree-item.pug +11 -7
  27. package/themes/umberto/layout/gloria/_components/nav-tree/nav-tree-level.pug +3 -3
  28. package/themes/umberto/layout/gloria/_components/snippet-footer/_style.scss +26 -0
  29. package/themes/umberto/layout/gloria/_components/snippet-footer/index.pug +10 -0
  30. package/themes/umberto/layout/gloria/_components/svg/index.pug +1 -1
  31. package/themes/umberto/layout/gloria/_modules/algolia-search/index.pug +1 -0
  32. package/themes/umberto/layout/gloria/_modules/header/nav-project-select-dropdown.pug +8 -8
  33. package/themes/umberto/layout/gloria/_modules/header-nightly-info/index.pug +1 -0
  34. package/themes/umberto/layout/gloria/_modules/mobile-nav/index.pug +17 -17
  35. package/themes/umberto/layout/gloria/_modules/toc/_style.scss +1 -1
  36. package/themes/umberto/layout/gloria/api.pug +0 -1
  37. package/themes/umberto/source/gloria/assets/_fonts/Lato/Lato-Bold.ttf +0 -0
  38. package/themes/umberto/source/gloria/assets/_fonts/Lato/Lato-Bold.woff2 +0 -0
  39. package/themes/umberto/source/gloria/assets/_fonts/Lato/Lato-BoldItalic.ttf +0 -0
  40. package/themes/umberto/source/gloria/assets/_fonts/Lato/Lato-BoldItalic.woff2 +0 -0
  41. package/themes/umberto/source/gloria/assets/_fonts/Lato/Lato-Italic.ttf +0 -0
  42. package/themes/umberto/source/gloria/assets/_fonts/Lato/Lato-Italic.woff2 +0 -0
  43. package/themes/umberto/source/gloria/assets/_fonts/Lato/Lato-Regular.ttf +0 -0
  44. package/themes/umberto/source/gloria/assets/_fonts/Lato/Lato-Regular.woff2 +0 -0
  45. package/themes/umberto/source/gloria/assets/_img/icons/sparkles.svg +1 -0
  46. package/themes/umberto/src/gloria/css/_fonts.scss +39 -0
  47. package/themes/umberto/src/gloria/css/base/_inline-code.scss +4 -3
  48. package/themes/umberto/src/gloria/css/base/_links.scss +2 -1
  49. package/themes/umberto/src/gloria/css/base/_tables.scss +0 -4
  50. package/themes/umberto/src/gloria/css/components/_api-collapsing-list.scss +4 -0
  51. package/themes/umberto/src/gloria/css/components/_index.scss +2 -1
  52. package/themes/umberto/src/gloria/css/doc/_snippets.scss +1 -0
  53. package/themes/umberto/src/gloria/css/layout/_base.scss +0 -10
  54. package/themes/umberto/src/gloria/css/utilities/_spacing.scss +1 -0
  55. package/themes/umberto/src/gloria/js/components/code-block.js +7 -4
  56. package/themes/umberto/src/gloria/js/modules/api-filter.js +9 -4
package/CHANGELOG.md CHANGED
@@ -1,6 +1,23 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ ## [8.0.1](https://github.com/cksource/umberto/compare/v8.0.0...v8.0.1) (July 28, 2025)
5
+
6
+ ### Bug fixes
7
+
8
+ * The performance of the building and the behavior of components have been improved. The most important changes are listed below:
9
+
10
+ * Improved the performance of the `validate-links` task by processing links in parallel across multiple CPU cores, instead of a single core.
11
+ * Enhanced the API filters behavior: now, when the `inherited` filter is unchecked while `internal` is selected, items tagged with both `inherited` and `internal` will be properly hidden from the results.
12
+ * Added the Lato font for improved typography and visual consistency.
13
+ * Restored the default selection color for content on the website to ensure a familiar and accessible user experience.
14
+ * Added a footer snippet for consistent branding and navigation across all pages.
15
+ * Improved the styling of `code` tags in API documentation for better readability and clarity.
16
+ * Added a new `sparkles` icon to the icon set.
17
+ * Fixed the project selection dropdown: after rebuilding, it now correctly displays all available projects instead of only one.
18
+ * Optimized the performance of the navigation tree building process, resulting in faster page loads and smoother navigation.
19
+
20
+
4
21
  ## [8.0.0](https://github.com/cksource/umberto/compare/v7.0.2...v8.0.0) (July 18, 2025)
5
22
 
6
23
  ### BREAKING CHANGES
@@ -48,13 +65,6 @@ Changelog
48
65
 
49
66
  * Support for rendering TypeScript API pages based on output from `typedoc@0.28`. Closes [#1188](https://github.com/cksource/umberto/issues/1188). ([commit](https://github.com/cksource/umberto/commit/561f94c6b025a0f1dbcc01c0c0e70ee5eeae387e))
50
67
 
51
-
52
- ## [6.1.2](https://github.com/cksource/umberto/compare/v6.1.1...v6.1.2) (2025-04-23)
53
-
54
- ### Bug fixes
55
-
56
- * Umberto attempts to load the theme's favicons in case a project does not define its own, rather than generating links to non-existent resources. Closes [#1256](https://github.com/cksource/umberto/issues/1256). ([commit](https://github.com/cksource/umberto/commit/a6de17b195a67e78010773f420e54fa16b154378))
57
-
58
68
  ---
59
69
 
60
70
  To see all releases, visit the [release page](https://github.com/cksource/umberto/releases).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "umberto",
3
- "version": "8.0.0",
3
+ "version": "8.0.1",
4
4
  "description": "CKSource Documentation builder",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -6,8 +6,23 @@
6
6
  'use strict';
7
7
 
8
8
  const cheerio = require( 'cheerio' );
9
- const renderPugComponent = require( '../../../utils/pug-renderer/render-pug-component' );
10
- const hexoManager = require( '../../../../src/hexo-manager' );
9
+ const createPrerenderPugTemplate = require( '../../../utils/pug-renderer/create-prerender-pug-template' );
10
+
11
+ /**
12
+ * Renders the button using Pug template.
13
+ */
14
+ const renderButton = createPrerenderPugTemplate( {
15
+ requires: [
16
+ '_components/svg/index',
17
+ '_components/icon/index',
18
+ '_components/tooltip-popover/index',
19
+ '_components/heading-link/index'
20
+ ],
21
+ component: 'heading-link',
22
+ componentAttrs: {
23
+ mask: [ 'headingId' ]
24
+ }
25
+ } );
11
26
 
12
27
  /**
13
28
  * Enforce priority 30 to run it after apply design doc classes filter.
@@ -34,8 +49,6 @@ hexo.extend.filter.register( 'after_post_render', page => {
34
49
 
35
50
  // Create the copy button
36
51
  const button = renderButton( {
37
- hexo: hexoManager.hexo,
38
- page,
39
52
  headingId
40
53
  } );
41
54
 
@@ -51,28 +64,6 @@ hexo.extend.filter.register( 'after_post_render', page => {
51
64
  return page;
52
65
  }, 30 );
53
66
 
54
- /**
55
- * Renders the button using Pug template.
56
- */
57
- function renderButton( { hexo, page, headingId } ) {
58
- return renderPugComponent( {
59
- hexo,
60
- requires: [
61
- '_components/svg/index',
62
- '_components/icon/index',
63
- '_components/tooltip-popover/index',
64
- '_components/heading-link/index'
65
- ],
66
- mixinContextVars: {
67
- page
68
- },
69
- component: 'heading-link',
70
- componentAttrs: {
71
- headingId
72
- }
73
- } );
74
- }
75
-
76
67
  /**
77
68
  * Removes all empty anchors that were created to hold the heading links buttons.
78
69
  */
@@ -12,4 +12,4 @@ const parseIconTag = require( '../../utils/parseicontag' );
12
12
  */
13
13
  hexo.extend.filter.register( 'after_post_render', page => {
14
14
  return parseIconTag( page, hexo );
15
- } );
15
+ }, 40 );
@@ -11,4 +11,4 @@ const inlineSvg = require( '../../../utils/inline-svg' );
11
11
  * Inlines SVG icons into HTML elements with data-inline-svg-image attribute.
12
12
  * The attribute value should contain the path to the SVG file.
13
13
  */
14
- hexo.extend.filter.register( 'after_render:html', inlineSvg );
14
+ hexo.extend.filter.register( 'after_render:html', inlineSvg, 500 );
@@ -11,4 +11,4 @@ const spritesheetSvg = require( '../../../utils/spritesheet-svg' );
11
11
  * Creates a spritesheet from SVG files referenced by data-spritesheet-svg attributes
12
12
  * and injects it at the beginning of the body with display: none.
13
13
  */
14
- hexo.extend.filter.register( 'after_render:html', spritesheetSvg );
14
+ hexo.extend.filter.register( 'after_render:html', spritesheetSvg, 499 );
@@ -12,6 +12,12 @@ const concatUrlParts = require( '../../../utils/concat-url-parts' );
12
12
  const relative_url = require( 'hexo/dist/plugins/helper/relative_url' ); // eslint-disable-line camelcase
13
13
  const dropInitSlash = require( '../../../utils/drop-init-slash' );
14
14
 
15
+ /**
16
+ * `hexo.model` calls are REALLY slow, so we cache them. It takes approx
17
+ * 10s to load all of these pages.
18
+ */
19
+ let PAGES;
20
+
15
21
  /**
16
22
  * Adds breadcrumbs data to the page by finding links to parent categories.
17
23
  *
@@ -43,7 +49,8 @@ hexo.extend.filter.register( 'before_post_render', page => {
43
49
  const { categoryIds, config } = projectGlobals;
44
50
 
45
51
  const basePath = hexo.projectGlobals[ page.projectName ].BASE_PATH;
46
- const pages = hexo.model( 'Page' ).toArray();
52
+
53
+ PAGES ||= hexo.model( 'Page' ).toArray();
47
54
 
48
55
  // Get all categories and groups from the project globals.
49
56
  const categoriesBreadcrumbs = getAllParentCategories( categoryIds, page.category )
@@ -70,7 +77,7 @@ hexo.extend.filter.register( 'before_post_render', page => {
70
77
  // is placed within directory of another category but is mapped
71
78
  // to the different category in `umberto.json`.
72
79
  const path = ( () => {
73
- const overviewPage = pages.find(
80
+ const overviewPage = PAGES.find(
74
81
  nestedPage =>
75
82
  nestedPage.category === category.id &&
76
83
  isOverviewPage( nestedPage )
@@ -143,6 +143,19 @@ const PATTERN_ELEMENTS = [
143
143
  ]
144
144
  },
145
145
 
146
+ // Labels
147
+ {
148
+ pattern: /(?:ck:)?snippet-footer$/,
149
+ mixinName: 'snippet-footer',
150
+ allowMarkdownContent: true,
151
+ requires: [
152
+ '_components/svg/index',
153
+ '_components/icon/index',
154
+ '_components/icon-message/index',
155
+ '_components/snippet-footer/index'
156
+ ]
157
+ },
158
+
146
159
  // Code block
147
160
  {
148
161
  pattern: 'ck:code-block',
@@ -25,13 +25,19 @@ const POST_RENDER_COMPONENTS = [
25
25
  '_components/skeleton/index',
26
26
  '_components/code-block/index'
27
27
  ],
28
- skipCacheIf: ( { code } ) => code?.split( '\n' ).length > 1,
28
+ createCacheKey: ( _, { copyable, language, skeletonLines } ) => {
29
+ const linesCacheKey = skeletonLines < 6 ?
30
+ skeletonLines :
31
+ Math.floor( skeletonLines / 5 ) + 100;
32
+
33
+ return `code-block-${ language }-${ copyable }-${ linesCacheKey }`;
34
+ },
29
35
  component: 'code-block',
30
36
  componentAttrs: {
31
37
  static: {
32
38
  copyable: true
33
39
  },
34
- dynamic: [ 'copyable', 'language' ],
40
+ dynamic: [ 'copyable', 'language', 'skeletonLines' ],
35
41
  mask: [ 'code' ]
36
42
  }
37
43
  } );
@@ -45,10 +51,12 @@ const POST_RENDER_COMPONENTS = [
45
51
 
46
52
  // Get the language from the class (e.g., "language-js" -> "js")
47
53
  const language = $code.attr( 'class' ).replace( 'doc', '' ).trim();
54
+ const code = $code.html();
48
55
 
49
56
  return template( {
50
- code: $code.html(),
51
- language
57
+ code,
58
+ language,
59
+ skeletonLines: code.trim().split( '\n' ).length
52
60
  } );
53
61
  };
54
62
  } )()
@@ -69,7 +77,7 @@ hexo.extend.filter.register( 'after_post_render', page => {
69
77
  return;
70
78
  }
71
79
 
72
- $ = $ || cheerio.load( page.content );
80
+ $ = $ || cheerio.load( page.content, null, false );
73
81
 
74
82
  $( component.selector ).each( ( i, element ) => {
75
83
  const $element = $( element );
@@ -91,4 +99,4 @@ hexo.extend.filter.register( 'after_post_render', page => {
91
99
  }
92
100
 
93
101
  return page;
94
- } );
102
+ }, 100 );
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @license Copyright (c) 2017-2025, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md.
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const cheerio = require( 'cheerio' );
9
+ const CACHED_TITLES = new Map();
10
+
11
+ hexo.extend.helper.register( 'uExtractAndCacheTitle', ( cacheKey, data ) => {
12
+ if ( !cacheKey ) {
13
+ throw new Error( 'Cache key is required for uExtractAndCacheTitle helper.' );
14
+ }
15
+
16
+ if ( CACHED_TITLES.has( cacheKey ) ) {
17
+ return CACHED_TITLES.get( cacheKey );
18
+ }
19
+
20
+ const $ = cheerio.load( data, null, false );
21
+ const title = $( 'h1:not( .live-snippet h1 )' ).first();
22
+ const formattedTitle = (
23
+ title
24
+ .children()
25
+ .remove()
26
+ .end()
27
+ .text()
28
+ .trim()
29
+ .replace( /</g, '&lt;' )
30
+ .replace( />/g, '&gt;' )
31
+ );
32
+
33
+ CACHED_TITLES.set( cacheKey, formattedTitle );
34
+
35
+ return formattedTitle;
36
+ } );
@@ -63,15 +63,22 @@ const renderPugComponent = require( './render-pug-component' );
63
63
  * // This will render a new version for 'html' and cache it.
64
64
  * const html3 = codeBlockTemplate( { language: 'html', code: '<h1>Hello</h1>' } );
65
65
  */
66
- module.exports = function createPrerenderPugTemplate( { componentAttrs, skipCacheIf, ...renderAttrs } ) {
66
+ module.exports = function createPrerenderPugTemplate(
67
+ {
68
+ componentAttrs,
69
+ skipCacheIf,
70
+ createCacheKey = createDefaultCacheKey,
71
+ ...renderAttrs
72
+ }
73
+ ) {
67
74
  const cacheStorage = new Map();
68
75
  const maskAttrsMap = assignMaskAttrsIds( componentAttrs.mask || [] );
69
76
 
70
- const allKnownAttributes = [
77
+ const allKnownAttributes = new Set( [
71
78
  ...componentAttrs.dynamic || [],
72
79
  ...Object.keys( componentAttrs.static || {} ),
73
80
  ...componentAttrs.mask || []
74
- ];
81
+ ] );
75
82
 
76
83
  return dynamicAttrs => {
77
84
  // Check if we should skip caching based on the provided condition.
@@ -130,7 +137,13 @@ module.exports = function createPrerenderPugTemplate( { componentAttrs, skipCach
130
137
  * Checks if the provided component attributes contain any unknown attributes.
131
138
  */
132
139
  function hasUnknownAttributes( knownAttributes, componentAttrs ) {
133
- return Object.keys( componentAttrs ).some( attr => !knownAttributes.includes( attr ) );
140
+ for ( const attr in componentAttrs ) {
141
+ if ( !knownAttributes.has( attr ) ) {
142
+ return true;
143
+ }
144
+ }
145
+
146
+ return false;
134
147
  }
135
148
 
136
149
  /**
@@ -140,7 +153,7 @@ function hasUnknownAttributes( knownAttributes, componentAttrs ) {
140
153
  * @param componentAttrs An object containing component attributes and their values.
141
154
  * @returns The generated cache key.
142
155
  */
143
- function createCacheKey( cacheByAttributes, componentAttrs ) {
156
+ function createDefaultCacheKey( cacheByAttributes, componentAttrs ) {
144
157
  if ( !cacheByAttributes?.length ) {
145
158
  return 'default';
146
159
  }
@@ -28,6 +28,13 @@ function randomId( prefix, maskable = true ) {
28
28
  return id;
29
29
  };
30
30
 
31
+ /**
32
+ * Checks if the given ID is a masked ID.
33
+ */
34
+ function isMaskedID( id ) {
35
+ return id.startsWith( 'gen-' );
36
+ }
37
+
31
38
  /**
32
39
  * Regenerates random IDs in a string.
33
40
  *
@@ -62,6 +69,7 @@ function regenerateRandomIds( str ) {
62
69
  }
63
70
 
64
71
  module.exports = {
72
+ isMaskedID,
65
73
  randomId,
66
74
  regenerateRandomIds
67
75
  };
@@ -25,6 +25,7 @@ const umbertoVersion = require( '../../../package.json' ).version;
25
25
  * @param {Array} extraStylePaths Paths to extra external css.
26
26
  * @param {Array} extraScriptsPaths Paths to extra external js.
27
27
  * @param {Boolean} disableSearch Extra flag for disabling docsearch if needed.
28
+ * @param {Array} quickNavigationProjects Projects to display in the quick navigation dropdown.
28
29
  * @param {Boolean} navigationShowEmptyCategories If set on true, empty categories will be displayed.
29
30
  * @param {Object} og Open Graph config.
30
31
  */
@@ -42,6 +43,7 @@ module.exports = ( ctx, {
42
43
  extraScriptsPaths,
43
44
  disableSearch,
44
45
  og,
46
+ quickNavigationProjects,
45
47
  navigationShowEmptyCategories
46
48
  } = {} ) => {
47
49
  ctx.extend.filter.register( 'template_locals', locals => {
@@ -84,6 +86,7 @@ module.exports = ( ctx, {
84
86
  locals.projectsData = [];
85
87
  }
86
88
 
89
+ locals.quickNavigationProjects = quickNavigationProjects;
87
90
  locals.projectsData.push( {
88
91
  name: projectName,
89
92
  slug: projectSlug,
@@ -64,7 +64,7 @@ module.exports = async config => {
64
64
  }
65
65
  );
66
66
 
67
- console.log( `Building API docs of ${ projectConfig.name }...` );
67
+ console.log( `Building API docs of ${ projectConfig.name } ...` );
68
68
  console.time( `Built API docs of ${ projectConfig.name } in` );
69
69
  const buildInfo = await apiBuilder.buildApi();
70
70
  console.timeEnd( `Built API docs of ${ projectConfig.name } in` );
@@ -151,13 +151,18 @@ module.exports = options => {
151
151
  additionalDocumentation: mainConfig.additionalDocumentation,
152
152
  canonicalUrlBeginning: mainConfig.canonicalUrlBeginning,
153
153
  macrosVariables: mainConfig.variables,
154
+ quickNavigationProjects: mainConfig.quickNavigationProjects || [
155
+ { name: 'CKEditor 5', slug: 'ckeditor5' },
156
+ { name: 'Cloud Services', slug: 'cs' },
157
+ { name: 'CKBox', slug: 'ckbox' }
158
+ ],
154
159
  guides,
155
160
  skipGuides
156
161
  } );
157
162
  } )
158
163
  .then( () => hexoManager.generate( {
159
164
  watch,
160
- concurrency: 50
165
+ concurrency: 80
161
166
  } ) )
162
167
  .then( () => buildSnippets( hexoManager.hexo.projectGlobals ) )
163
168
  .then( () => copyProjectIcons( hexoManager.hexo.projectGlobals, hexoManager.getPublicDir() ) )
@@ -276,7 +281,8 @@ async function buildProjects( rootPath, projectPaths, options = {} ) {
276
281
  feedbackWidget: options.feedbackWidget,
277
282
  og: options.og,
278
283
  canonicalUrlBeginning: options.canonicalUrlBeginning,
279
- macrosVariables: options.macrosVariables
284
+ macrosVariables: options.macrosVariables,
285
+ quickNavigationProjects: options.quickNavigationProjects
280
286
  } )
281
287
  );
282
288
  }
@@ -297,7 +303,8 @@ async function buildProjects( rootPath, projectPaths, options = {} ) {
297
303
  feedbackWidget: options.feedbackWidget,
298
304
  og: options.og,
299
305
  canonicalUrlBeginning: options.canonicalUrlBeginning,
300
- macrosVariables: options.macrosVariables
306
+ macrosVariables: options.macrosVariables,
307
+ quickNavigationProjects: options.quickNavigationProjects
301
308
  } ) );
302
309
  }
303
310
 
@@ -347,6 +354,7 @@ async function buildProjects( rootPath, projectPaths, options = {} ) {
347
354
  googletagmanager: options.googletagmanager,
348
355
  googleanalytics: options.googleanalytics,
349
356
  promobar: options.promobar,
357
+ quickNavigationProjects: options.quickNavigationProjects,
350
358
  vwo: options.vwo,
351
359
  feedbackWidget: options.feedbackWidget,
352
360
  extraStylePaths: extraStyles,
@@ -439,6 +447,7 @@ async function buildApis( projectConfigs, options = {} ) {
439
447
  macrosVariables: options.macrosVariables,
440
448
  templateLocals: {
441
449
  projectsData: basicProjectsData,
450
+ quickNavigationProjects: options.quickNavigationProjects,
442
451
  extraStylePaths: options.extraStyles,
443
452
  extraScriptsPaths: options.extraScripts,
444
453
  sitemap: config.sitemap || options.sitemap,
@@ -535,6 +544,7 @@ function buildSdks( projectConfigs, options = {} ) {
535
544
  googleoptimize: options.googleoptimize,
536
545
  googletagmanager: options.googletagmanager,
537
546
  googleanalytics: options.googleanalytics,
547
+ quickNavigationProjects: options.quickNavigationProjects,
538
548
  promobar: options.promobar,
539
549
  vwo: options.vwo,
540
550
  feedbackWidget: options.feedbackWidget,