Merge branch 'develop' into weeman1337/mute-broadcast-notifications
This commit is contained in:
commit
804f0925df
8 changed files with 85 additions and 24 deletions
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { forwardRef, RefObject, useRef } from "react";
|
import React, { ForwardedRef, forwardRef, MutableRefObject, useRef } from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
import EditorStateTransfer from "../../../../utils/EditorStateTransfer";
|
import EditorStateTransfer from "../../../../utils/EditorStateTransfer";
|
||||||
|
@ -24,16 +24,18 @@ import { useWysiwygEditActionHandler } from "./hooks/useWysiwygEditActionHandler
|
||||||
import { useEditing } from "./hooks/useEditing";
|
import { useEditing } from "./hooks/useEditing";
|
||||||
import { useInitialContent } from "./hooks/useInitialContent";
|
import { useInitialContent } from "./hooks/useInitialContent";
|
||||||
import { ComposerContext, getDefaultContextValue } from "./ComposerContext";
|
import { ComposerContext, getDefaultContextValue } from "./ComposerContext";
|
||||||
|
import { ComposerFunctions } from "./types";
|
||||||
|
|
||||||
interface ContentProps {
|
interface ContentProps {
|
||||||
disabled: boolean;
|
disabled?: boolean;
|
||||||
|
composerFunctions: ComposerFunctions;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Content = forwardRef<HTMLElement, ContentProps>(function Content(
|
const Content = forwardRef<HTMLElement, ContentProps>(function Content(
|
||||||
{ disabled }: ContentProps,
|
{ disabled = false, composerFunctions }: ContentProps,
|
||||||
forwardRef: RefObject<HTMLElement>,
|
forwardRef: ForwardedRef<HTMLElement>,
|
||||||
) {
|
) {
|
||||||
useWysiwygEditActionHandler(disabled, forwardRef);
|
useWysiwygEditActionHandler(disabled, forwardRef as MutableRefObject<HTMLElement>, composerFunctions);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -65,9 +67,9 @@ export default function EditWysiwygComposer({ editorStateTransfer, className, ..
|
||||||
onSend={editMessage}
|
onSend={editMessage}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{(ref) => (
|
{(ref, composerFunctions) => (
|
||||||
<>
|
<>
|
||||||
<Content disabled={props.disabled} ref={ref} />
|
<Content disabled={props.disabled} ref={ref} composerFunctions={composerFunctions} />
|
||||||
<EditionButtons
|
<EditionButtons
|
||||||
onCancelClick={endEditing}
|
onCancelClick={endEditing}
|
||||||
onSaveClick={editMessage}
|
onSaveClick={editMessage}
|
||||||
|
|
|
@ -22,8 +22,6 @@ import dis from "../../../../../dispatcher/dispatcher";
|
||||||
import { ComposerInsertPayload } from "../../../../../dispatcher/payloads/ComposerInsertPayload";
|
import { ComposerInsertPayload } from "../../../../../dispatcher/payloads/ComposerInsertPayload";
|
||||||
import { Action } from "../../../../../dispatcher/actions";
|
import { Action } from "../../../../../dispatcher/actions";
|
||||||
import { useRoomContext } from "../../../../../contexts/RoomContext";
|
import { useRoomContext } from "../../../../../contexts/RoomContext";
|
||||||
import { useComposerContext } from "../ComposerContext";
|
|
||||||
import { setSelection } from "../utils/selection";
|
|
||||||
|
|
||||||
interface EmojiProps {
|
interface EmojiProps {
|
||||||
menuPosition: AboveLeftOf;
|
menuPosition: AboveLeftOf;
|
||||||
|
@ -31,19 +29,16 @@ interface EmojiProps {
|
||||||
|
|
||||||
export function Emoji({ menuPosition }: EmojiProps) {
|
export function Emoji({ menuPosition }: EmojiProps) {
|
||||||
const roomContext = useRoomContext();
|
const roomContext = useRoomContext();
|
||||||
const composerContext = useComposerContext();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EmojiButton
|
<EmojiButton
|
||||||
menuPosition={menuPosition}
|
menuPosition={menuPosition}
|
||||||
addEmoji={(emoji) => {
|
addEmoji={(emoji) => {
|
||||||
setSelection(composerContext.selection).then(() =>
|
dis.dispatch<ComposerInsertPayload>({
|
||||||
dis.dispatch<ComposerInsertPayload>({
|
action: Action.ComposerInsert,
|
||||||
action: Action.ComposerInsert,
|
text: emoji,
|
||||||
text: emoji,
|
timelineRenderingType: roomContext.timelineRenderingType,
|
||||||
timelineRenderingType: roomContext.timelineRenderingType,
|
});
|
||||||
}),
|
|
||||||
);
|
|
||||||
return true;
|
return true;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -22,9 +22,18 @@ import { ActionPayload } from "../../../../../dispatcher/payloads";
|
||||||
import { TimelineRenderingType, useRoomContext } from "../../../../../contexts/RoomContext";
|
import { TimelineRenderingType, useRoomContext } from "../../../../../contexts/RoomContext";
|
||||||
import { useDispatcher } from "../../../../../hooks/useDispatcher";
|
import { useDispatcher } from "../../../../../hooks/useDispatcher";
|
||||||
import { focusComposer } from "./utils";
|
import { focusComposer } from "./utils";
|
||||||
|
import { ComposerType } from "../../../../../dispatcher/payloads/ComposerInsertPayload";
|
||||||
|
import { ComposerFunctions } from "../types";
|
||||||
|
import { setSelection } from "../utils/selection";
|
||||||
|
import { useComposerContext } from "../ComposerContext";
|
||||||
|
|
||||||
export function useWysiwygEditActionHandler(disabled: boolean, composerElement: RefObject<HTMLElement>) {
|
export function useWysiwygEditActionHandler(
|
||||||
|
disabled: boolean,
|
||||||
|
composerElement: RefObject<HTMLElement>,
|
||||||
|
composerFunctions: ComposerFunctions,
|
||||||
|
) {
|
||||||
const roomContext = useRoomContext();
|
const roomContext = useRoomContext();
|
||||||
|
const composerContext = useComposerContext();
|
||||||
const timeoutId = useRef<number | null>(null);
|
const timeoutId = useRef<number | null>(null);
|
||||||
|
|
||||||
const handler = useCallback(
|
const handler = useCallback(
|
||||||
|
@ -39,9 +48,17 @@ export function useWysiwygEditActionHandler(disabled: boolean, composerElement:
|
||||||
case Action.FocusEditMessageComposer:
|
case Action.FocusEditMessageComposer:
|
||||||
focusComposer(composerElement, context, roomContext, timeoutId);
|
focusComposer(composerElement, context, roomContext, timeoutId);
|
||||||
break;
|
break;
|
||||||
|
case Action.ComposerInsert:
|
||||||
|
if (payload.timelineRenderingType !== roomContext.timelineRenderingType) break;
|
||||||
|
if (payload.composerType !== ComposerType.Edit) break;
|
||||||
|
|
||||||
|
if (payload.text) {
|
||||||
|
setSelection(composerContext.selection).then(() => composerFunctions.insertText(payload.text));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[disabled, composerElement, timeoutId, roomContext],
|
[disabled, composerElement, composerFunctions, timeoutId, roomContext, composerContext],
|
||||||
);
|
);
|
||||||
|
|
||||||
useDispatcher(defaultDispatcher, handler);
|
useDispatcher(defaultDispatcher, handler);
|
||||||
|
|
|
@ -24,6 +24,8 @@ import { useDispatcher } from "../../../../../hooks/useDispatcher";
|
||||||
import { focusComposer } from "./utils";
|
import { focusComposer } from "./utils";
|
||||||
import { ComposerFunctions } from "../types";
|
import { ComposerFunctions } from "../types";
|
||||||
import { ComposerType } from "../../../../../dispatcher/payloads/ComposerInsertPayload";
|
import { ComposerType } from "../../../../../dispatcher/payloads/ComposerInsertPayload";
|
||||||
|
import { useComposerContext } from "../ComposerContext";
|
||||||
|
import { setSelection } from "../utils/selection";
|
||||||
|
|
||||||
export function useWysiwygSendActionHandler(
|
export function useWysiwygSendActionHandler(
|
||||||
disabled: boolean,
|
disabled: boolean,
|
||||||
|
@ -31,6 +33,7 @@ export function useWysiwygSendActionHandler(
|
||||||
composerFunctions: ComposerFunctions,
|
composerFunctions: ComposerFunctions,
|
||||||
) {
|
) {
|
||||||
const roomContext = useRoomContext();
|
const roomContext = useRoomContext();
|
||||||
|
const composerContext = useComposerContext();
|
||||||
const timeoutId = useRef<number | null>(null);
|
const timeoutId = useRef<number | null>(null);
|
||||||
|
|
||||||
const handler = useCallback(
|
const handler = useCallback(
|
||||||
|
@ -59,12 +62,12 @@ export function useWysiwygSendActionHandler(
|
||||||
} else if (payload.event) {
|
} else if (payload.event) {
|
||||||
// TODO insert quote message - see SendMessageComposer
|
// TODO insert quote message - see SendMessageComposer
|
||||||
} else if (payload.text) {
|
} else if (payload.text) {
|
||||||
composerFunctions.insertText(payload.text);
|
setSelection(composerContext.selection).then(() => composerFunctions.insertText(payload.text));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[disabled, composerElement, composerFunctions, timeoutId, roomContext],
|
[disabled, composerElement, roomContext, composerFunctions, composerContext],
|
||||||
);
|
);
|
||||||
|
|
||||||
useDispatcher(defaultDispatcher, handler);
|
useDispatcher(defaultDispatcher, handler);
|
||||||
|
|
|
@ -953,7 +953,6 @@
|
||||||
"Temporary implementation. Locations persist in room history.": "Temporary implementation. Locations persist in room history.",
|
"Temporary implementation. Locations persist in room history.": "Temporary implementation. Locations persist in room history.",
|
||||||
"Favourite Messages": "Favourite Messages",
|
"Favourite Messages": "Favourite Messages",
|
||||||
"Under active development.": "Under active development.",
|
"Under active development.": "Under active development.",
|
||||||
"Under active development": "Under active development",
|
|
||||||
"Force 15s voice broadcast chunk length": "Force 15s voice broadcast chunk length",
|
"Force 15s voice broadcast chunk length": "Force 15s voice broadcast chunk length",
|
||||||
"Use new session manager": "Use new session manager",
|
"Use new session manager": "Use new session manager",
|
||||||
"New session manager": "New session manager",
|
"New session manager": "New session manager",
|
||||||
|
|
|
@ -459,7 +459,6 @@ export const SETTINGS: { [setting: string]: ISetting } = {
|
||||||
labsGroup: LabGroup.Messaging,
|
labsGroup: LabGroup.Messaging,
|
||||||
supportedLevels: LEVELS_FEATURE,
|
supportedLevels: LEVELS_FEATURE,
|
||||||
displayName: _td("Voice broadcast"),
|
displayName: _td("Voice broadcast"),
|
||||||
description: _td("Under active development"),
|
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
[Features.VoiceBroadcastForceSmallChunks]: {
|
[Features.VoiceBroadcastForceSmallChunks]: {
|
||||||
|
|
|
@ -26,6 +26,12 @@ import { IRoomState } from "../../../../../src/components/structures/RoomView";
|
||||||
import { createTestClient, flushPromises, getRoomContext, mkEvent, mkStubRoom } from "../../../../test-utils";
|
import { createTestClient, flushPromises, getRoomContext, mkEvent, mkStubRoom } from "../../../../test-utils";
|
||||||
import { EditWysiwygComposer } from "../../../../../src/components/views/rooms/wysiwyg_composer";
|
import { EditWysiwygComposer } from "../../../../../src/components/views/rooms/wysiwyg_composer";
|
||||||
import EditorStateTransfer from "../../../../../src/utils/EditorStateTransfer";
|
import EditorStateTransfer from "../../../../../src/utils/EditorStateTransfer";
|
||||||
|
import { Emoji } from "../../../../../src/components/views/rooms/wysiwyg_composer/components/Emoji";
|
||||||
|
import { ChevronFace } from "../../../../../src/components/structures/ContextMenu";
|
||||||
|
import dis from "../../../../../src/dispatcher/dispatcher";
|
||||||
|
import { ComposerInsertPayload, ComposerType } from "../../../../../src/dispatcher/payloads/ComposerInsertPayload";
|
||||||
|
import { ActionPayload } from "../../../../../src/dispatcher/payloads";
|
||||||
|
import * as EmojiButton from "../../../../../src/components/views/rooms/EmojiButton";
|
||||||
|
|
||||||
describe("EditWysiwygComposer", () => {
|
describe("EditWysiwygComposer", () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
@ -269,4 +275,44 @@ describe("EditWysiwygComposer", () => {
|
||||||
// Then we don't get it because we are disabled
|
// Then we don't get it because we are disabled
|
||||||
expect(screen.getByRole("textbox")).not.toHaveFocus();
|
expect(screen.getByRole("textbox")).not.toHaveFocus();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should add emoji", async () => {
|
||||||
|
// When
|
||||||
|
|
||||||
|
// We are not testing here the emoji button (open modal, select emoji ...)
|
||||||
|
// Instead we are directly firing an emoji to make the test easier to write
|
||||||
|
jest.spyOn(EmojiButton, "EmojiButton").mockImplementation(
|
||||||
|
({ addEmoji }: { addEmoji: (emoji: string) => void }) => {
|
||||||
|
return (
|
||||||
|
<button aria-label="Emoji" type="button" onClick={() => addEmoji("🦫")}>
|
||||||
|
Emoji
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
render(
|
||||||
|
<MatrixClientContext.Provider value={mockClient}>
|
||||||
|
<RoomContext.Provider value={defaultRoomContext}>
|
||||||
|
<EditWysiwygComposer editorStateTransfer={editorStateTransfer} />
|
||||||
|
<Emoji menuPosition={{ chevronFace: ChevronFace.Top }} />
|
||||||
|
</RoomContext.Provider>
|
||||||
|
</MatrixClientContext.Provider>,
|
||||||
|
);
|
||||||
|
// Same behavior as in RoomView.tsx
|
||||||
|
// RoomView is re-dispatching the composer messages.
|
||||||
|
// It adds the composerType fields where the value refers if the composer is in editing or not
|
||||||
|
// The listeners in the RTE ignore the message if the composerType is missing in the payload
|
||||||
|
const dispatcherRef = dis.register((payload: ActionPayload) => {
|
||||||
|
dis.dispatch<ComposerInsertPayload>({
|
||||||
|
...(payload as ComposerInsertPayload),
|
||||||
|
composerType: ComposerType.Edit,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
screen.getByLabelText("Emoji").click();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
await waitFor(() => expect(screen.getByRole("textbox")).toHaveTextContent(/🦫/));
|
||||||
|
dis.unregister(dispatcherRef);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -294,7 +294,7 @@ describe("SendWysiwygComposer", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const textNode = screen.getByRole("textbox").firstChild;
|
const textNode = screen.getByRole("textbox").firstChild;
|
||||||
setSelection({
|
await setSelection({
|
||||||
anchorNode: textNode,
|
anchorNode: textNode,
|
||||||
anchorOffset: 2,
|
anchorOffset: 2,
|
||||||
focusNode: textNode,
|
focusNode: textNode,
|
||||||
|
|
Loading…
Reference in a new issue