@@ -12,6 +12,7 @@ import { CommonInternalSettings } from '../../tools/base';
12
12
import type { Popover , PopoverItemHtmlParams , PopoverItemParams , WithChildren } from '../../utils/popover' ;
13
13
import { PopoverItemType } from '../../utils/popover' ;
14
14
import { PopoverInline } from '../../utils/popover/popover-inline' ;
15
+ import type InlineToolAdapter from 'src/components/tools/inline' ;
15
16
16
17
/**
17
18
* Inline Toolbar elements
@@ -54,7 +55,7 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
54
55
/**
55
56
* Currently visible tools instances
56
57
*/
57
- private toolsInstances : Map < string , IInlineTool > | null = new Map ( ) ;
58
+ private tools : Map < InlineToolAdapter , IInlineTool > = new Map ( ) ;
58
59
59
60
/**
60
61
* @param moduleConfiguration - Module Configuration
@@ -66,21 +67,10 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
66
67
config,
67
68
eventsDispatcher,
68
69
} ) ;
69
- }
70
70
71
- /**
72
- * Toggles read-only mode
73
- *
74
- * @param {boolean } readOnlyEnabled - read-only mode
75
- */
76
- public toggleReadOnly ( readOnlyEnabled : boolean ) : void {
77
- if ( ! readOnlyEnabled ) {
78
- window . requestIdleCallback ( ( ) => {
79
- this . make ( ) ;
80
- } , { timeout : 2000 } ) ;
81
- } else {
82
- this . destroy ( ) ;
83
- }
71
+ window . requestIdleCallback ( ( ) => {
72
+ this . make ( ) ;
73
+ } , { timeout : 2000 } ) ;
84
74
}
85
75
86
76
/**
@@ -116,14 +106,10 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
116
106
return ;
117
107
}
118
108
119
- if ( this . Editor . ReadOnly . isEnabled ) {
120
- return ;
121
- }
122
-
123
- Array . from ( this . toolsInstances . entries ( ) ) . forEach ( ( [ name , toolInstance ] ) => {
124
- const shortcut = this . getToolShortcut ( name ) ;
109
+ for ( const [ tool , toolInstance ] of this . tools ) {
110
+ const shortcut = this . getToolShortcut ( tool . name ) ;
125
111
126
- if ( shortcut ) {
112
+ if ( shortcut !== undefined ) {
127
113
Shortcuts . remove ( this . Editor . UI . nodes . redactor , shortcut ) ;
128
114
}
129
115
@@ -133,9 +119,9 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
133
119
if ( _ . isFunction ( toolInstance . clear ) ) {
134
120
toolInstance . clear ( ) ;
135
121
}
136
- } ) ;
122
+ }
137
123
138
- this . toolsInstances = null ;
124
+ this . tools = new Map ( ) ;
139
125
140
126
this . reset ( ) ;
141
127
this . opened = false ;
@@ -204,10 +190,12 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
204
190
this . popover . destroy ( ) ;
205
191
}
206
192
207
- const inlineTools = await this . getInlineTools ( ) ;
193
+ this . createToolsInstances ( ) ;
194
+
195
+ const popoverItems = await this . getPopoverItems ( ) ;
208
196
209
197
this . popover = new PopoverInline ( {
210
- items : inlineTools ,
198
+ items : popoverItems ,
211
199
scopeElement : this . Editor . API . methods . ui . nodes . redactor ,
212
200
messages : {
213
201
nothingFound : I18n . ui ( I18nInternalNS . ui . popover , 'Nothing found' ) ,
@@ -290,25 +278,36 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
290
278
return false ;
291
279
}
292
280
293
- if ( currentSelection && tagsConflictsWithSelection . includes ( target . tagName ) ) {
281
+ if ( currentSelection !== null && tagsConflictsWithSelection . includes ( target . tagName ) ) {
294
282
return false ;
295
283
}
296
284
297
- // The selection of the element only in contenteditable
298
- const contenteditable = target . closest ( '[contenteditable="true"]' ) ;
285
+ /**
286
+ * Check if there is at leas one tool enabled by current Block's Tool
287
+ */
288
+ const currentBlock = this . Editor . BlockManager . getBlock ( currentSelection . anchorNode as HTMLElement ) ;
299
289
300
- if ( contenteditable === null ) {
290
+ if ( ! currentBlock ) {
301
291
return false ;
302
292
}
303
293
304
- // is enabled by current Block's Tool
305
- const currentBlock = this . Editor . BlockManager . getBlock ( currentSelection . anchorNode as HTMLElement ) ;
294
+ /**
295
+ * Check that at least one tool is available for the current block
296
+ */
297
+ const toolsAvailable = this . getTools ( ) ;
298
+ const isAtLeastOneToolAvailable = toolsAvailable . some ( ( tool ) => currentBlock . tool . inlineTools . has ( tool . name ) ) ;
306
299
307
- if ( ! currentBlock ) {
300
+ if ( isAtLeastOneToolAvailable === false ) {
308
301
return false ;
309
302
}
310
303
311
- return currentBlock . tool . inlineTools . size !== 0 ;
304
+ /**
305
+ * Inline toolbar will be shown only if the target is contenteditable
306
+ * In Read-Only mode, the target should be contenteditable with "false" value
307
+ */
308
+ const contenteditable = target . closest ( '[contenteditable]' ) ;
309
+
310
+ return contenteditable !== null ;
312
311
}
313
312
314
313
/**
@@ -317,32 +316,63 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
317
316
*/
318
317
319
318
/**
320
- * Returns Inline Tools segregated by their appearance type: popover items and custom html elements.
321
- * Sets this.toolsInstances map
319
+ * Returns tools that are available for current block
320
+ *
321
+ * Used to check if Inline Toolbar could be shown
322
+ * and to render tools in the Inline Toolbar
322
323
*/
323
- private async getInlineTools ( ) : Promise < PopoverItemParams [ ] > {
324
- const currentSelection = SelectionUtils . get ( ) ;
325
- const currentBlock = this . Editor . BlockManager . getBlock ( currentSelection . anchorNode as HTMLElement ) ;
324
+ private getTools ( ) : InlineToolAdapter [ ] {
325
+ const currentBlock = this . Editor . BlockManager . currentBlock ;
326
+
327
+ if ( ! currentBlock ) {
328
+ return [ ] ;
329
+ }
326
330
327
331
const inlineTools = Array . from ( currentBlock . tool . inlineTools . values ( ) ) ;
328
332
329
- const popoverItems = [ ] as PopoverItemParams [ ] ;
333
+ return inlineTools . filter ( ( tool ) => {
334
+ /**
335
+ * We support inline tools in read only mode.
336
+ * Such tools should have isReadOnlySupported flag set to true
337
+ */
338
+ if ( this . Editor . ReadOnly . isEnabled && tool . isReadOnlySupported !== true ) {
339
+ return false ;
340
+ }
330
341
331
- if ( this . toolsInstances === null ) {
332
- this . toolsInstances = new Map ( ) ;
333
- }
342
+ return true ;
343
+ } ) ;
344
+ }
345
+
346
+ /**
347
+ * Constructs tools instances and saves them to this.tools
348
+ */
349
+ private createToolsInstances ( ) : void {
350
+ this . tools = new Map ( ) ;
334
351
335
- for ( let i = 0 ; i < inlineTools . length ; i ++ ) {
336
- const tool = inlineTools [ i ] ;
352
+ const tools = this . getTools ( ) ;
353
+
354
+ tools . forEach ( ( tool ) => {
337
355
const instance = tool . create ( ) ;
338
- const renderedTool = await instance . render ( ) ;
339
356
340
- this . toolsInstances . set ( tool . name , instance ) ;
357
+ this . tools . set ( tool , instance ) ;
358
+ } ) ;
359
+ }
360
+
361
+ /**
362
+ * Returns Popover Items for tools segregated by their appearance type: regular items and custom html elements.
363
+ */
364
+ private async getPopoverItems ( ) : Promise < PopoverItemParams [ ] > {
365
+ const popoverItems = [ ] as PopoverItemParams [ ] ;
366
+
367
+ let i = 0 ;
368
+
369
+ for ( const [ tool , instance ] of this . tools ) {
370
+ const renderedTool = await instance . render ( ) ;
341
371
342
372
/** Enable tool shortcut */
343
373
const shortcut = this . getToolShortcut ( tool . name ) ;
344
374
345
- if ( shortcut ) {
375
+ if ( shortcut !== undefined ) {
346
376
try {
347
377
this . enableShortcuts ( tool . name , shortcut ) ;
348
378
} catch ( e ) { }
@@ -429,7 +459,9 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
429
459
type : PopoverItemType . Default ,
430
460
} as PopoverItemParams ;
431
461
432
- /** Prepend with separator if item has children and not the first one */
462
+ /**
463
+ * Prepend the separator if item has children and not the first one
464
+ */
433
465
if ( 'children' in popoverItem && i !== 0 ) {
434
466
popoverItems . push ( {
435
467
type : PopoverItemType . Separator ,
@@ -438,14 +470,18 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
438
470
439
471
popoverItems . push ( popoverItem ) ;
440
472
441
- /** Append separator after the item is it has children and not the last one */
442
- if ( 'children' in popoverItem && i < inlineTools . length - 1 ) {
473
+ /**
474
+ * Append a separator after the item if it has children and not the last one
475
+ */
476
+ if ( 'children' in popoverItem && i < this . tools . size - 1 ) {
443
477
popoverItems . push ( {
444
478
type : PopoverItemType . Separator ,
445
479
} ) ;
446
480
}
447
481
}
448
482
} ) ;
483
+
484
+ i ++ ;
449
485
}
450
486
451
487
return popoverItems ;
@@ -533,7 +569,7 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
533
569
* Check Tools` state by selection
534
570
*/
535
571
private checkToolsState ( ) : void {
536
- this . toolsInstances ?. forEach ( ( toolInstance ) => {
572
+ this . tools ?. forEach ( ( toolInstance ) => {
537
573
toolInstance . checkState ?.( SelectionUtils . get ( ) ) ;
538
574
} ) ;
539
575
}
0 commit comments