@@ -12,6 +12,7 @@ import { CommonInternalSettings } from '../../tools/base';
1212import type { Popover , PopoverItemHtmlParams , PopoverItemParams , WithChildren } from '../../utils/popover' ;
1313import { PopoverItemType } from '../../utils/popover' ;
1414import { PopoverInline } from '../../utils/popover/popover-inline' ;
15+ import type InlineToolAdapter from 'src/components/tools/inline' ;
1516
1617/**
1718 * Inline Toolbar elements
@@ -54,7 +55,7 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
5455 /**
5556 * Currently visible tools instances
5657 */
57- private toolsInstances : Map < string , IInlineTool > | null = new Map ( ) ;
58+ private tools : Map < InlineToolAdapter , IInlineTool > = new Map ( ) ;
5859
5960 /**
6061 * @param moduleConfiguration - Module Configuration
@@ -66,21 +67,10 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
6667 config,
6768 eventsDispatcher,
6869 } ) ;
69- }
7070
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 } ) ;
8474 }
8575
8676 /**
@@ -116,14 +106,10 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
116106 return ;
117107 }
118108
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 ) ;
125111
126- if ( shortcut ) {
112+ if ( shortcut !== undefined ) {
127113 Shortcuts . remove ( this . Editor . UI . nodes . redactor , shortcut ) ;
128114 }
129115
@@ -133,9 +119,9 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
133119 if ( _ . isFunction ( toolInstance . clear ) ) {
134120 toolInstance . clear ( ) ;
135121 }
136- } ) ;
122+ }
137123
138- this . toolsInstances = null ;
124+ this . tools = new Map ( ) ;
139125
140126 this . reset ( ) ;
141127 this . opened = false ;
@@ -204,10 +190,12 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
204190 this . popover . destroy ( ) ;
205191 }
206192
207- const inlineTools = await this . getInlineTools ( ) ;
193+ this . createToolsInstances ( ) ;
194+
195+ const popoverItems = await this . getPopoverItems ( ) ;
208196
209197 this . popover = new PopoverInline ( {
210- items : inlineTools ,
198+ items : popoverItems ,
211199 scopeElement : this . Editor . API . methods . ui . nodes . redactor ,
212200 messages : {
213201 nothingFound : I18n . ui ( I18nInternalNS . ui . popover , 'Nothing found' ) ,
@@ -290,25 +278,36 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
290278 return false ;
291279 }
292280
293- if ( currentSelection && tagsConflictsWithSelection . includes ( target . tagName ) ) {
281+ if ( currentSelection !== null && tagsConflictsWithSelection . includes ( target . tagName ) ) {
294282 return false ;
295283 }
296284
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 ) ;
299289
300- if ( contenteditable === null ) {
290+ if ( ! currentBlock ) {
301291 return false ;
302292 }
303293
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 ) ) ;
306299
307- if ( ! currentBlock ) {
300+ if ( isAtLeastOneToolAvailable === false ) {
308301 return false ;
309302 }
310303
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 ;
312311 }
313312
314313 /**
@@ -317,32 +316,63 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
317316 */
318317
319318 /**
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
322323 */
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+ }
326330
327331 const inlineTools = Array . from ( currentBlock . tool . inlineTools . values ( ) ) ;
328332
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+ }
330341
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 ( ) ;
334351
335- for ( let i = 0 ; i < inlineTools . length ; i ++ ) {
336- const tool = inlineTools [ i ] ;
352+ const tools = this . getTools ( ) ;
353+
354+ tools . forEach ( ( tool ) => {
337355 const instance = tool . create ( ) ;
338- const renderedTool = await instance . render ( ) ;
339356
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 ( ) ;
341371
342372 /** Enable tool shortcut */
343373 const shortcut = this . getToolShortcut ( tool . name ) ;
344374
345- if ( shortcut ) {
375+ if ( shortcut !== undefined ) {
346376 try {
347377 this . enableShortcuts ( tool . name , shortcut ) ;
348378 } catch ( e ) { }
@@ -429,7 +459,9 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
429459 type : PopoverItemType . Default ,
430460 } as PopoverItemParams ;
431461
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+ */
433465 if ( 'children' in popoverItem && i !== 0 ) {
434466 popoverItems . push ( {
435467 type : PopoverItemType . Separator ,
@@ -438,14 +470,18 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
438470
439471 popoverItems . push ( popoverItem ) ;
440472
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 ) {
443477 popoverItems . push ( {
444478 type : PopoverItemType . Separator ,
445479 } ) ;
446480 }
447481 }
448482 } ) ;
483+
484+ i ++ ;
449485 }
450486
451487 return popoverItems ;
@@ -533,7 +569,7 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
533569 * Check Tools` state by selection
534570 */
535571 private checkToolsState ( ) : void {
536- this . toolsInstances ?. forEach ( ( toolInstance ) => {
572+ this . tools ?. forEach ( ( toolInstance ) => {
537573 toolInstance . checkState ?.( SelectionUtils . get ( ) ) ;
538574 } ) ;
539575 }
0 commit comments