@@ -255,7 +255,7 @@ describe('BridgePlugin', () => {
255255 mockedPlugin2 ,
256256 ] ) ;
257257
258- spyOn ( eventConverter , 'newEventToOldEvent' ) . and . callFake ( newEvent => {
258+ spyOn ( eventConverter , 'newEventToOldEvent' ) . and . callFake ( ( newEvent : any ) => {
259259 return ( 'NEW_' + newEvent ) as any ;
260260 } ) ;
261261
@@ -277,10 +277,10 @@ describe('BridgePlugin', () => {
277277
278278 it ( 'onPluginEvent without exclusive handling' , ( ) => {
279279 const initializeSpy = jasmine . createSpy ( 'initialize' ) ;
280- const onPluginEventSpy1 = jasmine . createSpy ( 'onPluginEvent1' ) . and . callFake ( event => {
280+ const onPluginEventSpy1 = jasmine . createSpy ( 'onPluginEvent1' ) . and . callFake ( ( event : any ) => {
281281 event . data = 'plugin1' ;
282282 } ) ;
283- const onPluginEventSpy2 = jasmine . createSpy ( 'onPluginEvent2' ) . and . callFake ( event => {
283+ const onPluginEventSpy2 = jasmine . createSpy ( 'onPluginEvent2' ) . and . callFake ( ( event : any ) => {
284284 event . data = 'plugin2' ;
285285 } ) ;
286286 const disposeSpy = jasmine . createSpy ( 'dispose' ) ;
@@ -305,7 +305,7 @@ describe('BridgePlugin', () => {
305305 mockedPlugin2 ,
306306 ] ) ;
307307
308- spyOn ( eventConverter , 'newEventToOldEvent' ) . and . callFake ( newEvent => {
308+ spyOn ( eventConverter , 'newEventToOldEvent' ) . and . callFake ( ( newEvent : any ) => {
309309 return {
310310 eventType : 'old_' + newEvent . eventType ,
311311 } as any ;
@@ -390,7 +390,7 @@ describe('BridgePlugin', () => {
390390 mockedPlugin2 ,
391391 ] ) ;
392392
393- spyOn ( eventConverter , 'newEventToOldEvent' ) . and . callFake ( newEvent => {
393+ spyOn ( eventConverter , 'newEventToOldEvent' ) . and . callFake ( ( newEvent : any ) => {
394394 return {
395395 eventType : 'old_' + newEvent . eventType ,
396396 eventDataCache : newEvent . eventDataCache ,
@@ -534,6 +534,302 @@ describe('BridgePlugin', () => {
534534 expect ( disposeSpy ) . toHaveBeenCalledTimes ( 2 ) ;
535535 } ) ;
536536
537+ it ( 'Context Menu provider with V9 providers' , ( ) => {
538+ const initializeSpy = jasmine . createSpy ( 'initialize' ) ;
539+ const onPluginEventSpy1 = jasmine . createSpy ( 'onPluginEvent1' ) ;
540+ const onPluginEventSpy2 = jasmine . createSpy ( 'onPluginEvent2' ) ;
541+ const onPluginEventSpy3 = jasmine . createSpy ( 'onPluginEvent3' ) ;
542+ const disposeSpy = jasmine . createSpy ( 'dispose' ) ;
543+ const queryElementsSpy = jasmine . createSpy ( 'queryElement' ) . and . returnValue ( [ ] ) ;
544+
545+ // V8 style context menu provider (1 argument)
546+ const getContextMenuItemsSpyV8 = jasmine
547+ . createSpy ( 'getContextMenuItems V8' )
548+ . and . returnValue ( [ 'item1' , 'item2' ] ) ;
549+
550+ // V9 style context menu provider (2 arguments) - create function with proper length
551+ const getContextMenuItemsSpyV9 = jasmine
552+ . createSpy ( 'getContextMenuItems V9' )
553+ . and . returnValue ( [ 'item3' , 'item4' ] ) ;
554+ // Override length property to simulate V9 function signature
555+ Object . defineProperty ( getContextMenuItemsSpyV9 , 'length' , { value : 2 } ) ;
556+
557+ const mockedPluginV8 = {
558+ initialize : initializeSpy ,
559+ onPluginEvent : onPluginEventSpy1 ,
560+ dispose : disposeSpy ,
561+ getContextMenuItems : getContextMenuItemsSpyV8 ,
562+ getName : ( ) => '' ,
563+ } as any ;
564+
565+ const mockedPluginV9 = {
566+ initialize : initializeSpy ,
567+ onPluginEvent : onPluginEventSpy2 ,
568+ dispose : disposeSpy ,
569+ getContextMenuItems : getContextMenuItemsSpyV9 ,
570+ getName : ( ) => '' ,
571+ initializeV9 : jasmine . createSpy ( 'initializeV9' ) ,
572+ } as any ;
573+
574+ const mockedPluginRegular = {
575+ initialize : initializeSpy ,
576+ onPluginEvent : onPluginEventSpy3 ,
577+ dispose : disposeSpy ,
578+ getName : ( ) => '' ,
579+ } as any ;
580+
581+ const mockedEditor = {
582+ queryElements : queryElementsSpy ,
583+ } as any ;
584+
585+ const onInitializeSpy = jasmine . createSpy ( 'onInitialize' ) . and . returnValue ( mockedEditor ) ;
586+ const plugin = new BridgePlugin . BridgePlugin ( onInitializeSpy , [
587+ mockedPluginV8 ,
588+ mockedPluginV9 ,
589+ mockedPluginRegular ,
590+ ] ) ;
591+
592+ const mockedZoomScale = 'ZOOM' as any ;
593+ const calculateZoomScaleSpy = jasmine
594+ . createSpy ( 'calculateZoomScale' )
595+ . and . returnValue ( mockedZoomScale ) ;
596+ const mockedColorManager = 'COLOR' as any ;
597+ const mockedInnerEditor = {
598+ getDOMHelper : ( ) => ( {
599+ calculateZoomScale : calculateZoomScaleSpy ,
600+ } ) ,
601+ getColorManager : ( ) => mockedColorManager ,
602+ getEnvironment : ( ) => {
603+ return {
604+ domToModelSettings : {
605+ customized : { } ,
606+ } ,
607+ } ;
608+ } ,
609+ } as any ;
610+ const mockedDarkColorHandler = 'COLOR' as any ;
611+ spyOn ( DarkColorHandler , 'createDarkColorHandler' ) . and . returnValue ( mockedDarkColorHandler ) ;
612+
613+ plugin . initialize ( mockedInnerEditor ) ;
614+
615+ expect ( onInitializeSpy ) . toHaveBeenCalledWith ( {
616+ customData : { } ,
617+ experimentalFeatures : [ ] ,
618+ sizeTransformer : jasmine . anything ( ) ,
619+ darkColorHandler : mockedDarkColorHandler ,
620+ edit : 'edit' ,
621+ contextMenuProviders : [ mockedPluginV8 , mockedPluginV9 ] ,
622+ } as any ) ;
623+
624+ const mockedNode = 'NODE' as any ;
625+ const mockedEvent = 'EVENT' as any ;
626+
627+ // Test that V9 provider receives both arguments, V8 provider receives only target
628+ const items = plugin . getContextMenuItems ( mockedNode , mockedEvent ) ;
629+
630+ expect ( items ) . toEqual ( [ 'item1' , 'item2' , null , 'item3' , 'item4' ] ) ;
631+ expect ( getContextMenuItemsSpyV8 ) . toHaveBeenCalledWith ( mockedNode ) ;
632+ expect ( getContextMenuItemsSpyV9 ) . toHaveBeenCalledWith ( mockedNode , mockedEvent ) ;
633+
634+ plugin . dispose ( ) ;
635+
636+ expect ( disposeSpy ) . toHaveBeenCalledTimes ( 3 ) ;
637+ } ) ;
638+
639+ it ( 'Context Menu provider with empty results' , ( ) => {
640+ const initializeSpy = jasmine . createSpy ( 'initialize' ) ;
641+ const disposeSpy = jasmine . createSpy ( 'dispose' ) ;
642+ const queryElementsSpy = jasmine . createSpy ( 'queryElement' ) . and . returnValue ( [ ] ) ;
643+
644+ // V8 provider returning empty array
645+ const getContextMenuItemsSpyV8Empty = jasmine
646+ . createSpy ( 'getContextMenuItems V8 Empty' )
647+ . and . returnValue ( [ ] ) ;
648+
649+ // V9 provider returning null
650+ const getContextMenuItemsSpyV9Null = jasmine
651+ . createSpy ( 'getContextMenuItems V9 Null' )
652+ . and . returnValue ( null ) ;
653+ Object . defineProperty ( getContextMenuItemsSpyV9Null , 'length' , { value : 2 } ) ;
654+
655+ // V9 provider returning items
656+ const getContextMenuItemsSpyV9Items = jasmine
657+ . createSpy ( 'getContextMenuItems V9 Items' )
658+ . and . returnValue ( [ 'item1' ] ) ;
659+ Object . defineProperty ( getContextMenuItemsSpyV9Items , 'length' , { value : 2 } ) ;
660+
661+ const mockedPluginV8Empty = {
662+ initialize : initializeSpy ,
663+ dispose : disposeSpy ,
664+ getContextMenuItems : getContextMenuItemsSpyV8Empty ,
665+ getName : ( ) => '' ,
666+ } as any ;
667+
668+ const mockedPluginV9Null = {
669+ initialize : initializeSpy ,
670+ dispose : disposeSpy ,
671+ getContextMenuItems : getContextMenuItemsSpyV9Null ,
672+ getName : ( ) => '' ,
673+ initializeV9 : jasmine . createSpy ( 'initializeV9' ) ,
674+ } as any ;
675+
676+ const mockedPluginV9Items = {
677+ initialize : initializeSpy ,
678+ dispose : disposeSpy ,
679+ getContextMenuItems : getContextMenuItemsSpyV9Items ,
680+ getName : ( ) => '' ,
681+ initializeV9 : jasmine . createSpy ( 'initializeV9' ) ,
682+ } as any ;
683+
684+ const mockedEditor = {
685+ queryElements : queryElementsSpy ,
686+ } as any ;
687+
688+ const onInitializeSpy = jasmine . createSpy ( 'onInitialize' ) . and . returnValue ( mockedEditor ) ;
689+ const plugin = new BridgePlugin . BridgePlugin ( onInitializeSpy , [
690+ mockedPluginV8Empty ,
691+ mockedPluginV9Null ,
692+ mockedPluginV9Items ,
693+ ] ) ;
694+
695+ const mockedZoomScale = 'ZOOM' as any ;
696+ const calculateZoomScaleSpy = jasmine
697+ . createSpy ( 'calculateZoomScale' )
698+ . and . returnValue ( mockedZoomScale ) ;
699+ const mockedColorManager = 'COLOR' as any ;
700+ const mockedInnerEditor = {
701+ getDOMHelper : ( ) => ( {
702+ calculateZoomScale : calculateZoomScaleSpy ,
703+ } ) ,
704+ getColorManager : ( ) => mockedColorManager ,
705+ getEnvironment : ( ) => {
706+ return {
707+ domToModelSettings : {
708+ customized : { } ,
709+ } ,
710+ } ;
711+ } ,
712+ } as any ;
713+ const mockedDarkColorHandler = 'COLOR' as any ;
714+ spyOn ( DarkColorHandler , 'createDarkColorHandler' ) . and . returnValue ( mockedDarkColorHandler ) ;
715+
716+ plugin . initialize ( mockedInnerEditor ) ;
717+
718+ const mockedNode = 'NODE' as any ;
719+ const mockedEvent = 'EVENT' as any ;
720+
721+ // Only the provider with items should contribute to the result
722+ const items = plugin . getContextMenuItems ( mockedNode , mockedEvent ) ;
723+
724+ expect ( items ) . toEqual ( [ 'item1' ] ) ;
725+ expect ( getContextMenuItemsSpyV8Empty ) . toHaveBeenCalledWith ( mockedNode ) ;
726+ expect ( getContextMenuItemsSpyV9Null ) . toHaveBeenCalledWith ( mockedNode , mockedEvent ) ;
727+ expect ( getContextMenuItemsSpyV9Items ) . toHaveBeenCalledWith ( mockedNode , mockedEvent ) ;
728+
729+ plugin . dispose ( ) ;
730+ } ) ;
731+
732+ it ( 'isV9ContextMenuProvider detection' , ( ) => {
733+ const initializeSpy = jasmine . createSpy ( 'initialize' ) ;
734+ const disposeSpy = jasmine . createSpy ( 'dispose' ) ;
735+
736+ // Function with 1 parameter (V8 style)
737+ const getContextMenuItemsV8 = jasmine
738+ . createSpy ( 'getContextMenuItems V8' )
739+ . and . returnValue ( [ 'item1' ] ) ;
740+ Object . defineProperty ( getContextMenuItemsV8 , 'length' , { value : 1 } ) ;
741+
742+ // Function with 2 parameters (V9 style)
743+ const getContextMenuItemsV9 = jasmine
744+ . createSpy ( 'getContextMenuItems V9' )
745+ . and . returnValue ( [ 'item2' ] ) ;
746+ Object . defineProperty ( getContextMenuItemsV9 , 'length' , { value : 2 } ) ;
747+
748+ // Function with 0 parameters
749+ const getContextMenuItemsZero = jasmine
750+ . createSpy ( 'getContextMenuItems Zero' )
751+ . and . returnValue ( [ 'item3' ] ) ;
752+ Object . defineProperty ( getContextMenuItemsZero , 'length' , { value : 0 } ) ;
753+
754+ // Function with 3 parameters
755+ const getContextMenuItemsThree = jasmine
756+ . createSpy ( 'getContextMenuItems Three' )
757+ . and . returnValue ( [ 'item4' ] ) ;
758+ Object . defineProperty ( getContextMenuItemsThree , 'length' , { value : 3 } ) ;
759+
760+ const mockedPluginV8 = {
761+ initialize : initializeSpy ,
762+ dispose : disposeSpy ,
763+ getContextMenuItems : getContextMenuItemsV8 ,
764+ getName : ( ) => 'V8Plugin' ,
765+ } as any ;
766+
767+ const mockedPluginV9 = {
768+ initialize : initializeSpy ,
769+ dispose : disposeSpy ,
770+ getContextMenuItems : getContextMenuItemsV9 ,
771+ getName : ( ) => 'V9Plugin' ,
772+ initializeV9 : jasmine . createSpy ( 'initializeV9' ) ,
773+ } as any ;
774+
775+ const mockedPluginZero = {
776+ initialize : initializeSpy ,
777+ dispose : disposeSpy ,
778+ getContextMenuItems : getContextMenuItemsZero ,
779+ getName : ( ) => 'ZeroPlugin' ,
780+ } as any ;
781+
782+ const mockedPluginThree = {
783+ initialize : initializeSpy ,
784+ dispose : disposeSpy ,
785+ getContextMenuItems : getContextMenuItemsThree ,
786+ getName : ( ) => 'ThreePlugin' ,
787+ } as any ;
788+
789+ const mockedEditor = { } as any ;
790+ const onInitializeSpy = jasmine . createSpy ( 'onInitialize' ) . and . returnValue ( mockedEditor ) ;
791+ const plugin = new BridgePlugin . BridgePlugin ( onInitializeSpy , [
792+ mockedPluginV8 ,
793+ mockedPluginV9 ,
794+ mockedPluginZero ,
795+ mockedPluginThree ,
796+ ] ) ;
797+
798+ const mockedInnerEditor = {
799+ getDOMHelper : ( ) => ( {
800+ calculateZoomScale : ( ) => 1 ,
801+ } ) ,
802+ getColorManager : ( ) => 'COLOR' ,
803+ getEnvironment : ( ) => {
804+ return {
805+ domToModelSettings : {
806+ customized : { } ,
807+ } ,
808+ } ;
809+ } ,
810+ } as any ;
811+
812+ spyOn ( DarkColorHandler , 'createDarkColorHandler' ) . and . returnValue ( 'COLOR' as any ) ;
813+
814+ plugin . initialize ( mockedInnerEditor ) ;
815+
816+ const mockedNode = 'NODE' as any ;
817+ const mockedEvent = 'EVENT' as any ;
818+
819+ const items = plugin . getContextMenuItems ( mockedNode , mockedEvent ) ;
820+
821+ // V8 plugins should be called with only target, V9 plugin should be called with both target and event
822+ expect ( getContextMenuItemsV8 ) . toHaveBeenCalledWith ( mockedNode ) ;
823+ expect ( getContextMenuItemsV9 ) . toHaveBeenCalledWith ( mockedNode , mockedEvent ) ;
824+ expect ( getContextMenuItemsZero ) . toHaveBeenCalledWith ( mockedNode ) ;
825+ expect ( getContextMenuItemsThree ) . toHaveBeenCalledWith ( mockedNode ) ;
826+
827+ // Only V9 plugin (length === 2) should receive the event parameter
828+ expect ( items ) . toEqual ( [ 'item1' , null , 'item2' , null , 'item3' , null , 'item4' ] ) ;
829+
830+ plugin . dispose ( ) ;
831+ } ) ;
832+
537833 it ( 'MixedPlugin' , ( ) => {
538834 const initializeV8Spy = jasmine . createSpy ( 'initializeV8' ) ;
539835 const initializeV9Spy = jasmine . createSpy ( 'initializeV9' ) ;
0 commit comments