jodit 4.17.6 → 4.18.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 (102) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/es2015/jodit.css +87 -3
  3. package/es2015/jodit.fat.min.css +1 -1
  4. package/es2015/jodit.fat.min.js +8 -8
  5. package/es2015/jodit.js +808 -132
  6. package/es2015/jodit.min.css +1 -1
  7. package/es2015/jodit.min.js +16 -16
  8. package/es2015/plugins/debug/debug.css +1 -1
  9. package/es2015/plugins/debug/debug.js +1 -1
  10. package/es2015/plugins/debug/debug.min.js +1 -1
  11. package/es2015/plugins/speech-recognize/speech-recognize.css +1 -1
  12. package/es2015/plugins/speech-recognize/speech-recognize.js +1 -1
  13. package/es2015/plugins/speech-recognize/speech-recognize.min.js +1 -1
  14. package/es2018/jodit.fat.min.css +1 -1
  15. package/es2018/jodit.fat.min.js +8 -8
  16. package/es2018/jodit.min.css +1 -1
  17. package/es2018/jodit.min.js +8 -8
  18. package/es2018/plugins/debug/debug.min.js +1 -1
  19. package/es2018/plugins/speech-recognize/speech-recognize.min.js +1 -1
  20. package/es2021/jodit.css +87 -3
  21. package/es2021/jodit.fat.min.css +1 -1
  22. package/es2021/jodit.fat.min.js +14 -14
  23. package/es2021/jodit.js +788 -132
  24. package/es2021/jodit.min.css +1 -1
  25. package/es2021/jodit.min.js +14 -14
  26. package/es2021/plugins/debug/debug.css +1 -1
  27. package/es2021/plugins/debug/debug.js +1 -1
  28. package/es2021/plugins/debug/debug.min.js +1 -1
  29. package/es2021/plugins/speech-recognize/speech-recognize.css +1 -1
  30. package/es2021/plugins/speech-recognize/speech-recognize.js +1 -1
  31. package/es2021/plugins/speech-recognize/speech-recognize.min.js +1 -1
  32. package/es2021.en/jodit.css +87 -3
  33. package/es2021.en/jodit.fat.min.css +1 -1
  34. package/es2021.en/jodit.fat.min.js +26 -26
  35. package/es2021.en/jodit.js +788 -132
  36. package/es2021.en/jodit.min.css +1 -1
  37. package/es2021.en/jodit.min.js +12 -12
  38. package/es2021.en/plugins/debug/debug.css +1 -1
  39. package/es2021.en/plugins/debug/debug.js +1 -1
  40. package/es2021.en/plugins/debug/debug.min.js +1 -1
  41. package/es2021.en/plugins/speech-recognize/speech-recognize.css +1 -1
  42. package/es2021.en/plugins/speech-recognize/speech-recognize.js +1 -1
  43. package/es2021.en/plugins/speech-recognize/speech-recognize.min.js +1 -1
  44. package/es5/jodit.css +92 -6
  45. package/es5/jodit.fat.min.css +1 -1
  46. package/es5/jodit.fat.min.js +2 -2
  47. package/es5/jodit.js +1073 -192
  48. package/es5/jodit.min.css +3 -3
  49. package/es5/jodit.min.js +2 -2
  50. package/es5/plugins/debug/debug.css +1 -1
  51. package/es5/plugins/debug/debug.js +1 -1
  52. package/es5/plugins/debug/debug.min.js +1 -1
  53. package/es5/plugins/speech-recognize/speech-recognize.css +1 -1
  54. package/es5/plugins/speech-recognize/speech-recognize.js +1 -1
  55. package/es5/plugins/speech-recognize/speech-recognize.min.js +1 -1
  56. package/es5/polyfills.fat.min.js +1 -1
  57. package/es5/polyfills.js +1 -1
  58. package/es5/polyfills.min.js +1 -1
  59. package/esm/config.d.ts +65 -2
  60. package/esm/config.js +29 -2
  61. package/esm/core/constants.js +1 -1
  62. package/esm/core/helpers/utils/align.d.ts +11 -5
  63. package/esm/core/helpers/utils/align.js +28 -8
  64. package/esm/core/helpers/utils/index.d.ts +1 -0
  65. package/esm/core/helpers/utils/index.js +1 -0
  66. package/esm/core/helpers/utils/media-wrapper.d.ts +29 -0
  67. package/esm/core/helpers/utils/media-wrapper.js +63 -0
  68. package/esm/core/selection/selection.js +3 -3
  69. package/esm/modules/toolbar/button/button.d.ts +18 -0
  70. package/esm/modules/toolbar/button/button.js +75 -5
  71. package/esm/plugins/dtd/after-insert/remove-extra-br.js +6 -1
  72. package/esm/plugins/dtd/before-insert/check-block-nesting.js +16 -1
  73. package/esm/plugins/dtd/config.js +3 -0
  74. package/esm/plugins/font/config.d.ts +12 -0
  75. package/esm/plugins/font/config.js +25 -10
  76. package/esm/plugins/font/font-picker.d.ts +51 -0
  77. package/esm/plugins/font/font-picker.js +238 -0
  78. package/esm/plugins/font/font.js +12 -0
  79. package/esm/plugins/font/google-fonts.d.ts +65 -0
  80. package/esm/plugins/font/google-fonts.js +143 -0
  81. package/esm/plugins/image-properties/readers/index.js +2 -1
  82. package/esm/plugins/image-properties/writers/index.js +2 -2
  83. package/esm/plugins/inline-popup/config/items/img.js +10 -8
  84. package/esm/plugins/inline-popup/inline-popup.js +13 -6
  85. package/esm/plugins/media/config.d.ts +26 -1
  86. package/esm/plugins/media/config.js +1 -3
  87. package/esm/plugins/media/media.js +12 -4
  88. package/esm/plugins/video/config.js +24 -4
  89. package/esm/types/toolbar.d.ts +2 -0
  90. package/esm/types/types.d.ts +13 -1
  91. package/package.json +1 -1
  92. package/types/config.d.ts +65 -2
  93. package/types/core/helpers/utils/align.d.ts +11 -5
  94. package/types/core/helpers/utils/index.d.ts +1 -0
  95. package/types/core/helpers/utils/media-wrapper.d.ts +29 -0
  96. package/types/modules/toolbar/button/button.d.ts +18 -0
  97. package/types/plugins/font/config.d.ts +12 -0
  98. package/types/plugins/font/font-picker.d.ts +51 -0
  99. package/types/plugins/font/google-fonts.d.ts +65 -0
  100. package/types/plugins/media/config.d.ts +26 -1
  101. package/types/types/toolbar.d.ts +2 -0
  102. package/types/types/types.d.ts +13 -1
@@ -33,7 +33,12 @@ export function removeExtraBr(jodit, node) {
33
33
  if (Dom.findNotEmptySibling(br, false)) {
34
34
  return;
35
35
  }
36
- jodit.s.setCursorBefore(br);
36
+ // After a block is inserted the caret is already at the end of its
37
+ // text; moving it before the `<br>` would put it on a line of its own
38
+ // below the block (#1315)
39
+ if (!Dom.isOrContains(node, jodit.s.range.startContainer)) {
40
+ jodit.s.setCursorBefore(br);
41
+ }
37
42
  Dom.safeRemove(br);
38
43
  }
39
44
  }
@@ -19,13 +19,28 @@ export function checkBlockNesting(jodit, node) {
19
19
  let current = (_b = (_a = jodit.s.current()) === null || _a === void 0 ? void 0 : _a.parentElement) !== null && _b !== void 0 ? _b : null;
20
20
  while (current && current !== jodit.editor) {
21
21
  if (Dom.isBlock(current)) {
22
- if (jodit.o.dtd.blockLimits[current.nodeName.toLowerCase()]) {
22
+ // In DIV mode the caret's own empty block is a line, like
23
+ // `<p><br></p>`, not a container to insert into (#1315)
24
+ const isEmptyLine = !parent &&
25
+ Dom.isTag(current, jodit.o.enter) &&
26
+ Dom.isEmpty(current);
27
+ if (jodit.o.dtd.blockLimits[current.nodeName.toLowerCase()] &&
28
+ !isEmptyLine) {
23
29
  break;
24
30
  }
25
31
  parent = current;
26
32
  }
27
33
  current = current.parentElement;
28
34
  }
35
+ // A list that is all of the inserted content adds its items to the
36
+ // list of the item it goes into, as the browsers' own paste does
37
+ if (Dom.isLeaf(current) &&
38
+ Dom.isList(node) &&
39
+ Dom.isFragment(node.parentNode) &&
40
+ !Dom.findNotEmptySibling(node, false)) {
41
+ Dom.unwrap(node);
42
+ parent = current;
43
+ }
29
44
  if (parent) {
30
45
  jodit.s.setCursorAfter(parent);
31
46
  if (Dom.isEmpty(parent)) {
@@ -13,10 +13,12 @@ Config.prototype.dtd = {
13
13
  audio: 1,
14
14
  body: 1,
15
15
  caption: 1,
16
+ dd: 1,
16
17
  details: 1,
17
18
  dir: 1,
18
19
  div: 1,
19
20
  dl: 1,
21
+ dt: 1,
20
22
  fieldset: 1,
21
23
  figcaption: 1,
22
24
  figure: 1,
@@ -24,6 +26,7 @@ Config.prototype.dtd = {
24
26
  form: 1,
25
27
  header: 1,
26
28
  hgroup: 1,
29
+ li: 1,
27
30
  main: 1,
28
31
  menu: 1,
29
32
  nav: 1,
@@ -6,6 +6,18 @@
6
6
  declare module 'jodit/config' {
7
7
  interface Config {
8
8
  defaultFontSizePoints: 'px' | 'pt';
9
+ font: {
10
+ googleFonts: {
11
+ /**
12
+ * Adds the Google Fonts library to the font family dropdown, which then
13
+ * also lists the theme's fonts and the fonts the content uses. The
14
+ * address answers with the JSON of the Google Fonts Developer API:
15
+ * the API itself (`https://www.googleapis.com/webfonts/v1/webfonts?key=…`)
16
+ * or a proxy of it. Empty leaves the dropdown as it is
17
+ */
18
+ url: string;
19
+ };
20
+ };
9
21
  }
10
22
  }
11
23
  export {};
@@ -4,16 +4,23 @@
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
6
  import { Dom } from "../../core/dom/index.js";
7
+ import { isArray } from "../../core/helpers/checker/is-array.js";
7
8
  import { trimChars } from "../../core/helpers/string/trim.js";
8
9
  import { css } from "../../core/helpers/utils/css.js";
9
10
  import { Icon } from "../../core/ui/icon.js";
10
11
  import { Config } from "../../config.js";
11
12
  import fontIcon from "./icons/font.svg.js";
12
13
  import fontsizeIcon from "./icons/fontsize.svg.js";
14
+ import { UIFontPicker } from "./font-picker.js";
13
15
  /**
14
16
  * Default font-size points
15
17
  */
16
18
  Config.prototype.defaultFontSizePoints = 'px';
19
+ Config.prototype.font = {
20
+ googleFonts: {
21
+ url: ''
22
+ }
23
+ };
17
24
  Icon.set('font', fontIcon).set('fontsize', fontsizeIcon);
18
25
  Config.prototype.controls.fontsize = {
19
26
  command: 'fontsize',
@@ -78,6 +85,7 @@ Config.prototype.controls.fontsize = {
78
85
  return keySet.has(normalize(value.toString()));
79
86
  }
80
87
  };
88
+ const hadSelection = new WeakSet();
81
89
  Config.prototype.controls.font = {
82
90
  ...Config.prototype.controls.fontsize,
83
91
  command: 'fontname',
@@ -108,6 +116,9 @@ Config.prototype.controls.font = {
108
116
  catch (_a) { }
109
117
  return `<span data-style="${key}" style="${isAvailable ? `font-family: ${key}!important;` : ''}">${value}</span>`;
110
118
  },
119
+ popup: (editor, current, close, button) => editor.o.font.googleFonts.url
120
+ ? new UIFontPicker(editor, button, close)
121
+ : false,
111
122
  data: {
112
123
  cssRule: 'font-family',
113
124
  normalize: (v) => {
@@ -119,19 +130,23 @@ Config.prototype.controls.font = {
119
130
  },
120
131
  // When no font is explicitly set, the computed font-family equals the
121
132
  // editor's own default (e.g. `-apple-system, …`). Return '' so the
122
- // button shows the `Default` list entry instead of that raw stack.
123
- // See #1370
124
- value: (editor) => {
125
- const current = editor.s.current();
126
- if (!current) {
127
- return;
133
+ // button shows the list's `Default` entry, when it has one, instead of
134
+ // that raw stack. See #1370
135
+ value: (editor, button) => {
136
+ const current = editor.s.current(), box = current && Dom.closest(current, Dom.isElement, editor.editor);
137
+ // Until there is a selection the button shows the editor's own font,
138
+ // and afterwards the font of the last one
139
+ if (box) {
140
+ hadSelection.add(button);
128
141
  }
129
- const box = Dom.closest(current, Dom.isElement, editor.editor);
130
- if (!box) {
142
+ else if (hadSelection.has(button)) {
131
143
  return;
132
144
  }
133
- const value = css(box, 'font-family').toString();
134
- if (value === css(editor.editor, 'font-family').toString()) {
145
+ const value = css(box || editor.editor, 'font-family').toString(), { list } = button.control;
146
+ if (value === css(editor.editor, 'font-family').toString() &&
147
+ (isArray(list)
148
+ ? list.includes('')
149
+ : '' in (list !== null && list !== void 0 ? list : {}))) {
135
150
  return '';
136
151
  }
137
152
  return value;
@@ -0,0 +1,51 @@
1
+ /*!
2
+ * Jodit Editor (https://xdsoft.net/jodit/)
3
+ * Released under MIT see LICENSE.txt in the project root for license information.
4
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
+ */
6
+ /**
7
+ * @module plugins/font
8
+ */
9
+ import type { IJodit, IToolbarButton } from "../../types/index";
10
+ import { UIElement } from "../../core/ui/element";
11
+ /**
12
+ * The font family dropdown with Google Fonts. Under their own headings it
13
+ * lists the fonts the editor's styles give text and headings, the fonts the
14
+ * content uses, the control's list and the Google Fonts library
15
+ */
16
+ export declare class UIFontPicker extends UIElement<IJodit> {
17
+ private readonly __button;
18
+ private readonly __close;
19
+ className(): string;
20
+ private readonly __googleFonts;
21
+ private readonly __fonts;
22
+ private __observer;
23
+ constructor(jodit: IJodit, __button: IToolbarButton, __close: () => void);
24
+ private __render;
25
+ /**
26
+ * The fonts the editor's styles give text and each heading
27
+ */
28
+ private __themeFonts;
29
+ /**
30
+ * The fonts the content sets
31
+ */
32
+ private __usedFonts;
33
+ private __append;
34
+ /**
35
+ * Shows the names of the Google Fonts in view, and those just below it,
36
+ * in their own fonts. Setting every item's font up front would have the
37
+ * browser look for each of the library's families among the installed
38
+ * fonts the first time the list opens
39
+ */
40
+ private __observeGoogleFonts;
41
+ /**
42
+ * Keeps the editor's selection, as the toolbar buttons do
43
+ */
44
+ protected onMouseDown(e: MouseEvent): void;
45
+ protected onClick(e: MouseEvent): void;
46
+ /**
47
+ * The font the selected text has without a font of its own: its block's
48
+ */
49
+ private __blockFont;
50
+ destruct(): void;
51
+ }
@@ -0,0 +1,238 @@
1
+ /*!
2
+ * Jodit Editor (https://xdsoft.net/jodit/)
3
+ * Released under MIT see LICENSE.txt in the project root for license information.
4
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
+ */
6
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
7
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
8
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
9
+ r = Reflect.decorate(decorators, target, key, desc);
10
+ else
11
+ for (var i = decorators.length - 1; i >= 0; i--)
12
+ if (d = decorators[i])
13
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
15
+ };
16
+ import { component } from "../../core/decorators/component/component.js";
17
+ import { watch } from "../../core/decorators/watch/watch.js";
18
+ import { Dom } from "../../core/dom/dom.js";
19
+ import { uniqueUid } from "../../core/global.js";
20
+ import { isArray } from "../../core/helpers/checker/is-array.js";
21
+ import { attr } from "../../core/helpers/utils/attr.js";
22
+ import { css } from "../../core/helpers/utils/css.js";
23
+ import { keys } from "../../core/helpers/utils/utils.js";
24
+ import { UIElement } from "../../core/ui/element.js";
25
+ import { firstFamily, GoogleFonts } from "./google-fonts.js";
26
+ const HEADINGS = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
27
+ const GENERIC_FAMILIES = new Set([
28
+ 'serif',
29
+ 'sans-serif',
30
+ 'monospace',
31
+ 'cursive',
32
+ 'fantasy',
33
+ 'system-ui',
34
+ 'ui-serif',
35
+ 'ui-sans-serif',
36
+ 'ui-monospace',
37
+ 'ui-rounded'
38
+ ]);
39
+ /**
40
+ * A family that names a font, not a generic family or a vendor keyword such
41
+ * as `-apple-system`
42
+ */
43
+ function isFontName(family) {
44
+ return (Boolean(family) &&
45
+ !family.startsWith('-') &&
46
+ !GENERIC_FAMILIES.has(family));
47
+ }
48
+ /**
49
+ * The font family dropdown with Google Fonts. Under their own headings it
50
+ * lists the fonts the editor's styles give text and headings, the fonts the
51
+ * content uses, the control's list and the Google Fonts library
52
+ */
53
+ let UIFontPicker = class UIFontPicker extends UIElement {
54
+ className() {
55
+ return 'UIFontPicker';
56
+ }
57
+ constructor(jodit, __button, __close) {
58
+ super(jodit);
59
+ this.__button = __button;
60
+ this.__close = __close;
61
+ this.__fonts = new Map();
62
+ this.__observer = null;
63
+ this.__googleFonts = jodit.getInstance(GoogleFonts);
64
+ this.__render();
65
+ if (!this.__googleFonts.fonts.size) {
66
+ this.__googleFonts.ready.then(() => !this.isDestructed && this.__render());
67
+ }
68
+ }
69
+ __render() {
70
+ var _a, _b;
71
+ const { control } = this.__button, { list = {} } = control, listed = isArray(list)
72
+ ? list.map((key) => ({
73
+ value: key.toString(),
74
+ title: key.toString()
75
+ }))
76
+ : keys(list, false).map((key) => ({
77
+ value: key,
78
+ title: list[key].toString()
79
+ })), google = Array.from(this.__googleFonts.fonts.values(), (font) => ({
80
+ value: this.__googleFonts.value(font),
81
+ title: font.family,
82
+ font
83
+ })), byFamily = new Map();
84
+ [...google, ...listed].forEach(entry => byFamily.set(firstFamily(entry.value), entry));
85
+ const theme = new Map(), used = new Map();
86
+ // The theme's own fonts are listed too, so its body font can be chosen
87
+ // to take a font off
88
+ this.__themeFonts().forEach(fontFamily => {
89
+ var _a;
90
+ const family = firstFamily(fontFamily), title = fontFamily.split(',')[0].replace(/["']/g, '').trim(), entry = (_a = byFamily.get(family)) !== null && _a !== void 0 ? _a : (isFontName(family)
91
+ ? { value: fontFamily, title }
92
+ : undefined);
93
+ entry && !theme.has(family) && theme.set(family, entry);
94
+ });
95
+ this.__usedFonts().forEach(fontFamily => {
96
+ const family = firstFamily(fontFamily), entry = byFamily.get(family);
97
+ entry && !theme.has(family) && used.set(family, entry);
98
+ });
99
+ const defaultEntry = listed.find(entry => entry.value === ''), current = firstFamily((_b = (_a = control.value) === null || _a === void 0 ? void 0 : _a.call(control, this.j, this.__button)) !== null && _b !== void 0 ? _b : '');
100
+ Dom.detach(this.container);
101
+ this.__fonts.clear();
102
+ defaultEntry && this.__append(current, [defaultEntry]);
103
+ this.__append(current, [...theme.values()], 'Theme fonts');
104
+ this.__append(current, [...used.values()], 'Used fonts');
105
+ this.__append(current, listed.filter(entry => entry !== defaultEntry), 'System fonts');
106
+ this.__append(current, google, 'Google Fonts');
107
+ this.__observeGoogleFonts();
108
+ }
109
+ /**
110
+ * The fonts the editor's styles give text and each heading
111
+ */
112
+ __themeFonts() {
113
+ const { editor } = this.j, fonts = [css(editor, 'font-family').toString()];
114
+ HEADINGS.forEach(tag => {
115
+ const heading = this.j.createInside.element(tag, {
116
+ style: 'display: none'
117
+ });
118
+ Dom.append(editor, heading);
119
+ fonts.push(css(heading, 'font-family').toString());
120
+ Dom.safeRemove(heading);
121
+ });
122
+ return fonts;
123
+ }
124
+ /**
125
+ * The fonts the content sets
126
+ */
127
+ __usedFonts() {
128
+ return Array.from(this.j.editor.querySelectorAll('[style*="font-family"]'), element => element.style.fontFamily);
129
+ }
130
+ __append(current, entries, heading) {
131
+ if (!entries.length) {
132
+ return;
133
+ }
134
+ const { control } = this.__button, group = this.j.c.div(this.getFullElName('group'));
135
+ if (heading) {
136
+ const title = this.j.c.div(this.getFullElName('heading'), {
137
+ id: `${this.getFullElName('heading')}-${uniqueUid()}`
138
+ });
139
+ title.textContent = this.i18n(heading);
140
+ attr(group, { role: 'group', 'aria-labelledby': title.id });
141
+ Dom.append(group, title);
142
+ }
143
+ entries.forEach(entry => {
144
+ var _a, _b;
145
+ const item = this.j.c.element('button', {
146
+ type: 'button',
147
+ class: this.getFullElName('item'),
148
+ 'data-value': entry.value,
149
+ 'aria-pressed': firstFamily(entry.value) === current
150
+ });
151
+ if (entry.font) {
152
+ item.textContent = entry.title;
153
+ this.__fonts.set(item, entry.font);
154
+ }
155
+ else {
156
+ item.innerHTML =
157
+ (_b = (_a = control.childTemplate) === null || _a === void 0 ? void 0 : _a.call(control, this.j, entry.value, entry.title, this.__button)) !== null && _b !== void 0 ? _b : entry.title;
158
+ }
159
+ Dom.append(group, item);
160
+ });
161
+ Dom.append(this.container, group);
162
+ }
163
+ /**
164
+ * Shows the names of the Google Fonts in view, and those just below it,
165
+ * in their own fonts. Setting every item's font up front would have the
166
+ * browser look for each of the library's families among the installed
167
+ * fonts the first time the list opens
168
+ */
169
+ __observeGoogleFonts() {
170
+ this.j.async.requestAnimationFrame(() => {
171
+ var _a;
172
+ (_a = this.__observer) === null || _a === void 0 ? void 0 : _a.disconnect();
173
+ if (this.isDestructed || !this.__fonts.size) {
174
+ return;
175
+ }
176
+ const observer = new IntersectionObserver(entries => {
177
+ const fonts = [];
178
+ entries.forEach(({ isIntersecting, target }) => {
179
+ const font = this.__fonts.get(target);
180
+ if (isIntersecting && font) {
181
+ fonts.push(font);
182
+ css(target, {
183
+ fontFamily: this.__googleFonts.value(font)
184
+ });
185
+ observer.unobserve(target);
186
+ }
187
+ });
188
+ this.__googleFonts.preview(fonts);
189
+ }, {
190
+ root: this.container.parentElement,
191
+ rootMargin: '0px 0px 400px 0px'
192
+ });
193
+ this.__fonts.forEach((_, item) => observer.observe(item));
194
+ this.__observer = observer;
195
+ });
196
+ }
197
+ /**
198
+ * Keeps the editor's selection, as the toolbar buttons do
199
+ */
200
+ onMouseDown(e) {
201
+ e.preventDefault();
202
+ }
203
+ onClick(e) {
204
+ var _a;
205
+ const item = Dom.up(e.target, node => Dom.isHTMLElement(node) && node.hasAttribute('data-value'), this.container);
206
+ if (!item) {
207
+ return;
208
+ }
209
+ const value = (_a = attr(item, 'data-value')) !== null && _a !== void 0 ? _a : '', font = this.__googleFonts.find(value),
210
+ // The font the text has anyway is taken off rather than written
211
+ inherited = firstFamily(value) === firstFamily(this.__blockFont());
212
+ font && !inherited && this.__googleFonts.load(font);
213
+ this.j.execCommand('fontname', false, inherited ? '' : value);
214
+ this.__close();
215
+ }
216
+ /**
217
+ * The font the selected text has without a font of its own: its block's
218
+ */
219
+ __blockFont() {
220
+ const block = Dom.up(this.j.s.current(), Dom.isBlock, this.j.editor);
221
+ return css(block !== null && block !== void 0 ? block : this.j.editor, 'font-family').toString();
222
+ }
223
+ destruct() {
224
+ var _a;
225
+ (_a = this.__observer) === null || _a === void 0 ? void 0 : _a.disconnect();
226
+ super.destruct();
227
+ }
228
+ };
229
+ __decorate([
230
+ watch('container:mousedown')
231
+ ], UIFontPicker.prototype, "onMouseDown", null);
232
+ __decorate([
233
+ watch('container:click')
234
+ ], UIFontPicker.prototype, "onClick", null);
235
+ UIFontPicker = __decorate([
236
+ component
237
+ ], UIFontPicker);
238
+ export { UIFontPicker };
@@ -6,6 +6,7 @@
6
6
  import { pluginSystem } from "../../core/global.js";
7
7
  import { normalizeSize } from "../../core/helpers/index.js";
8
8
  import "./config.js";
9
+ import { GoogleFonts } from "./google-fonts.js";
9
10
  /**
10
11
  * Process commands `fontsize` and `fontname`
11
12
  */
@@ -19,6 +20,17 @@ export function font(editor) {
19
20
  name: 'fontsize',
20
21
  group: 'font'
21
22
  });
23
+ if (editor.o.font.googleFonts.url) {
24
+ const googleFonts = editor.getInstance(GoogleFonts), loadUsed = editor.async.debounce(() => googleFonts.loadUsed(), editor.defaultTimeout);
25
+ googleFonts.ready.then(loadUsed);
26
+ editor.e.on('afterInit afterSetMode change', loadUsed);
27
+ }
28
+ // An iframe's stylesheets can arrive after the toolbar first shows the
29
+ // editor's font
30
+ editor.e.on('afterInit', () => {
31
+ editor.iframe &&
32
+ editor.e.on(editor.ed, 'load', () => editor.e.fire('updateToolbar'), { capture: true });
33
+ });
22
34
  const callback = (command, second, third) => {
23
35
  switch (command) {
24
36
  case 'fontsize':
@@ -0,0 +1,65 @@
1
+ /*!
2
+ * Jodit Editor (https://xdsoft.net/jodit/)
3
+ * Released under MIT see LICENSE.txt in the project root for license information.
4
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
+ */
6
+ /**
7
+ * @module plugins/font
8
+ */
9
+ import type { IJodit } from "../../types/index";
10
+ import { ViewComponent } from "../../core/component/view-component";
11
+ /**
12
+ * A font as the Google Fonts Developer API describes it
13
+ */
14
+ export interface IGoogleFont {
15
+ family: string;
16
+ category: string;
17
+ variants: string[];
18
+ }
19
+ /**
20
+ * The first family of a `font-family` value, unquoted and in lower case for
21
+ * comparing
22
+ */
23
+ export declare function firstFamily(fontFamily: string): string;
24
+ /**
25
+ * Loads fonts from Google Fonts: the whole of each font the content uses into
26
+ * the editor's document, and just the letters of its name for the font list
27
+ */
28
+ export declare class GoogleFonts extends ViewComponent<IJodit> {
29
+ className(): string;
30
+ /**
31
+ * The library by lower-case family, empty until it arrives
32
+ */
33
+ readonly fonts: Map<string, IGoogleFont>;
34
+ readonly ready: Promise<void>;
35
+ private readonly __links;
36
+ private readonly __loaded;
37
+ private readonly __previewed;
38
+ constructor(jodit: IJodit);
39
+ /**
40
+ * The library's font named first in a `font-family` value
41
+ */
42
+ find(fontFamily: string): IGoogleFont | undefined;
43
+ /**
44
+ * The `font-family` value that applies a font
45
+ */
46
+ value(font: IGoogleFont): string;
47
+ /**
48
+ * Loads the regular, italic, bold and bold italic styles that a font has
49
+ * into the editor's document
50
+ */
51
+ load(font: IGoogleFont): void;
52
+ /**
53
+ * Loads every font of the library that the content uses
54
+ */
55
+ loadUsed(): void;
56
+ /**
57
+ * Loads into the page just the letters of each font's name, so the font
58
+ * list can show the name in its font
59
+ */
60
+ preview(fonts: IGoogleFont[]): void;
61
+ private __loadedInto;
62
+ private __family;
63
+ private __append;
64
+ destruct(): void;
65
+ }