import { Assertions, GeneralSteps, Logger, Step, UiFinder, Waiter } from '@ephox/agar'; import { UnitTest } from '@ephox/bedrock-client'; import { Optional, Result } from '@ephox/katamari'; import { Css, type SugarElement } from '@ephox/sugar'; import * as AddEventsBehaviour from 'ephox/alloy/api/behaviour/AddEventsBehaviour'; import * as Behaviour from 'ephox/alloy/api/behaviour/Behaviour'; import type { AlloyComponent } from 'ephox/alloy/api/component/ComponentApi'; import * as GuiFactory from 'ephox/alloy/api/component/GuiFactory'; import * as AlloyEvents from 'ephox/alloy/api/events/AlloyEvents'; import { Button } from 'ephox/alloy/api/ui/Button'; import { Container } from 'ephox/alloy/api/ui/Container'; import { InlineView } from 'ephox/alloy/api/ui/InlineView'; import * as Layout from 'ephox/alloy/positioning/layout/Layout'; import type { NodeAnchorSpec } from 'ephox/alloy/positioning/mode/Anchoring'; import * as GuiSetup from 'ephox/alloy/test/GuiSetup'; import * as Sinks from 'ephox/alloy/test/Sinks'; import * as TestBroadcasts from 'ephox/alloy/test/TestBroadcasts'; UnitTest.asynctest('InlineViewRepositionTest', (success, failure) => { GuiSetup.setup((_store, _doc, _body) => Sinks.relativeSink(), (_doc, _body, gui, component, store) => { const anchor = GuiFactory.build({ dom: { tag: 'div', styles: { 'height': '10px', 'width': '10px', 'background-color': 'red', 'position': 'fixed', 'top': '200px', 'left': '200px' } } }); const inline = GuiFactory.build( InlineView.sketch({ dom: { tag: 'div', classes: [ 'test-inline' ] }, lazySink: () => { return Result.value(component); }, fireRepositionEventInstead: { event: 'test-reposition' }, inlineBehaviours: Behaviour.derive([ AddEventsBehaviour.config('inline-reposition-test', [ AlloyEvents.run('test-reposition', store.adder('test-reposition-fired')) ]) ]) }) ); const inline2 = GuiFactory.build( InlineView.sketch({ dom: { tag: 'div', classes: [ 'test-inline2' ] }, lazySink: () => { return Result.value(component); } }) ); gui.add(anchor); const sCheckOpen = (label: string, component: AlloyComponent, selector: string) => Logger.t( label, GeneralSteps.sequence([ Waiter.sTryUntil( 'Test inline should not be DOM', UiFinder.sExists(gui.element, selector) ), Step.sync(() => { Assertions.assertEq('Checking isOpen API', true, InlineView.isOpen(component)); }) ]) ); const sCheckPosition = (label: string, element: SugarElement, x: number, y: number) => Logger.t( label, Step.sync(() => { const top = parseInt(Css.get(element, 'top').replace('px', ''), 10); const left = parseInt(Css.get(element, 'left').replace('px', ''), 10); Assertions.assertEq('Checking top position', y, top); Assertions.assertEq('Checking left position', x, left); }) ); const anchorSpec: NodeAnchorSpec = { type: 'node', root: gui.element, node: Optional.some(anchor.element), layouts: { onLtr: () => [ Layout.southeast ], onRtl: () => [ Layout.southeast ] } }; return [ Logger.t( 'Show inline view with custom reposition', GeneralSteps.sequence([ Step.sync(() => { InlineView.showAt(inline, Container.sketch({ components: [ Button.sketch({ uid: 'bold-button', dom: { tag: 'button', innerHtml: 'B', classes: [ 'bold-button' ] }, action: store.adder('bold') }) ] }), { anchor: anchorSpec }); }), sCheckPosition('Check initial position', inline.element, 200, 210), Step.sync(() => { Css.set(anchor.element, 'top', '150px'); Css.set(anchor.element, 'left', '150px'); }), TestBroadcasts.sReposition( 'should not move on custom reposition', gui ), sCheckOpen('Dialog should still be open', inline, '.test-inline'), sCheckPosition('Check inline view has not moved', inline.element, 200, 210), store.sAssertEq('Broadcasting SHOULD fire reposition event', [ 'test-reposition-fired' ]) ]) ), store.sClear, Step.sync(() => { InlineView.hide(inline); }), Logger.t( 'Show inline view with normal reposition', GeneralSteps.sequence([ Step.sync(() => { InlineView.showAt(inline2, Container.sketch({ components: [ Button.sketch({ uid: 'bold-button2', dom: { tag: 'button', innerHtml: 'B', classes: [ 'bold-button' ] }, action: store.adder('bold') }) ] }), { anchor: anchorSpec }); }), sCheckPosition('Check initial position', inline2.element, 150, 160), Step.sync(() => { Css.set(anchor.element, 'top', '200px'); Css.set(anchor.element, 'left', '200px'); }), TestBroadcasts.sReposition( 'should move on normal reposition', gui ), sCheckOpen('Dialog should still be open', inline2, '.test-inline2'), sCheckPosition('Check inline view has moved', inline2.element, 200, 210), store.sAssertEq('Broadcasting should NOT fire reposition event', [ ]) ]) ) ]; }, success, failure); });