From 46466f1d19fc26ccfd5227c18aa079ee33cb8b6c Mon Sep 17 00:00:00 2001 From: Botho <1258870+elbotho@users.noreply.github.com> Date: Tue, 19 Sep 2023 12:52:33 +0200 Subject: [PATCH 1/6] wip: cleanup --- src/serlo-editor/store/documents/saga.ts | 24 +++++++++++++++--------- src/serlo-editor/store/focus/slice.ts | 11 ++++++++--- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/serlo-editor/store/documents/saga.ts b/src/serlo-editor/store/documents/saga.ts index d54d8547ca..2a0e6c6aac 100644 --- a/src/serlo-editor/store/documents/saga.ts +++ b/src/serlo-editor/store/documents/saga.ts @@ -42,7 +42,9 @@ function* changeDocumentSaga(action: ReturnType) { handleRecursiveInserts, (helpers: StoreDeserializeHelpers) => { return stateHandler.initial(document.state, helpers) - } + }, + [], + true // shouldFocusInsertedDocument ) const createChange = (state: unknown): ReversibleAction => { @@ -118,7 +120,9 @@ function* changeDocumentSaga(action: ReturnType) { handleRecursiveInserts, (helpers: StoreDeserializeHelpers) => { return updater(currentDocument.state, helpers) - } + }, + [], + true // shouldFocusInsertedDocument ) payload.callback(resolveActions, pureResolveState) if (payload.resolve || payload.reject) { @@ -164,7 +168,8 @@ function* replaceDocumentSaga( const [actions]: [ReversibleAction[], unknown] = yield call( handleRecursiveInserts, () => {}, - pendingDocs + pendingDocs, + true // shouldFocusInsertedDocument ) const reversibleAction: ReversibleAction = { @@ -205,6 +210,7 @@ export function* handleRecursiveInserts( }, } const result = act(helpers) + for (let doc; (doc = pendingDocs.pop()); ) { const plugin = editorPlugins.getByType(doc.plugin) if (!plugin) { @@ -212,12 +218,12 @@ export function* handleRecursiveInserts( console.warn(`Invalid plugin '${doc.plugin}'`) continue } - let state: unknown - if (doc.state === undefined) { - state = plugin.state.createInitialState(helpers) - } else { - state = plugin.state.deserialize(doc.state, helpers) - } + + const state: unknown = + doc.state === undefined + ? plugin.state.createInitialState(helpers) + : plugin.state.deserialize(doc.state, helpers) + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const currentDocument: ReturnType = yield select( selectDocument, diff --git a/src/serlo-editor/store/focus/slice.ts b/src/serlo-editor/store/focus/slice.ts index 471013ca20..8be41d292d 100644 --- a/src/serlo-editor/store/focus/slice.ts +++ b/src/serlo-editor/store/focus/slice.ts @@ -1,7 +1,10 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { findNextChildTreeNode, findPreviousChildTreeNode } from './helpers' -import { type ChildTreeNode, isPureInsertDocumentAction } from '../documents' +import { + type ChildTreeNode, + isInsertAndFocusDocumentAction, +} from '../documents' import { State } from '../types' const initialState: State['focus'] = null as State['focus'] @@ -29,8 +32,10 @@ export const focusSlice = createSlice({ extraReducers: (builder) => { builder.addMatcher( // Always focus the newly inserted document - isPureInsertDocumentAction, - (_state, action) => action.payload.id + isInsertAndFocusDocumentAction, + (_state, action) => { + return action.payload.id + } ) }, }) From d96630796f73df5f7a677fd934eb72b7adc3ad84 Mon Sep 17 00:00:00 2001 From: Vitomir Budimir Date: Tue, 19 Sep 2023 10:46:18 +0200 Subject: [PATCH 2/6] test(editor store): control focus of newly inserted plugin --- src/serlo-editor/store/documents/matchers.ts | 10 +++++----- src/serlo-editor/store/documents/saga.ts | 9 +++++++-- src/serlo-editor/store/documents/slice.ts | 12 ++++++++++++ src/serlo-editor/store/documents/types.ts | 4 ++++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/serlo-editor/store/documents/matchers.ts b/src/serlo-editor/store/documents/matchers.ts index 81f9d65271..fafc65d8d7 100644 --- a/src/serlo-editor/store/documents/matchers.ts +++ b/src/serlo-editor/store/documents/matchers.ts @@ -1,10 +1,10 @@ import { AnyAction } from '@reduxjs/toolkit' -import { pureInsertDocument } from './slice' -import type { PureInsertDocumentAction } from './types' +import { insertAndFocusDocument } from './slice' +import type { InsertAndFocusDocumentAction } from './types' -export function isPureInsertDocumentAction( +export function isInsertAndFocusDocumentAction( action: AnyAction -): action is PureInsertDocumentAction { - return action.type === pureInsertDocument.type +): action is InsertAndFocusDocumentAction { + return action.type === insertAndFocusDocument.type } diff --git a/src/serlo-editor/store/documents/saga.ts b/src/serlo-editor/store/documents/saga.ts index 2a0e6c6aac..ece19fd265 100644 --- a/src/serlo-editor/store/documents/saga.ts +++ b/src/serlo-editor/store/documents/saga.ts @@ -9,6 +9,7 @@ import { pureRemoveDocument, pureReplaceDocument, runReplaceDocumentSaga, + insertAndFocusDocument, } from '.' import type { ReversibleAction } from '..' import { @@ -196,7 +197,8 @@ interface ChannelAction { export function* handleRecursiveInserts( act: (helpers: StoreDeserializeHelpers) => unknown, - initialDocuments: { id: string; plugin: string; state?: unknown }[] = [] + initialDocuments: { id: string; plugin: string; state?: unknown }[] = [], + shouldFocusInsertedDocument: boolean = false ) { const actions: ReversibleAction[] = [] const pendingDocs: { @@ -243,8 +245,11 @@ export function* handleRecursiveInserts( }), }) } else { + const action = shouldFocusInsertedDocument + ? insertAndFocusDocument + : pureInsertDocument actions.push({ - action: pureInsertDocument({ + action: action({ id: doc.id, plugin: doc.plugin, state, diff --git a/src/serlo-editor/store/documents/slice.ts b/src/serlo-editor/store/documents/slice.ts index 1d4b906061..85ec86cc19 100644 --- a/src/serlo-editor/store/documents/slice.ts +++ b/src/serlo-editor/store/documents/slice.ts @@ -1,6 +1,7 @@ import { createSlice } from '@reduxjs/toolkit' import type { + InsertAndFocusDocumentAction, PureChangeDocumentAction, PureInsertDocumentAction, PureRemoveDocumentAction, @@ -14,6 +15,16 @@ export const documentsSlice = createSlice({ name: 'documents', initialState, reducers: { + // The insert action with a side effect: + // Focus the newly inserted document (see `focus` slice) + insertAndFocusDocument(state, action: InsertAndFocusDocumentAction) { + const { id, plugin: type, state: pluginState } = action.payload + state[id] = { + plugin: type, + state: pluginState, + } + }, + // The pure insert action (no side effects) pureInsertDocument(state, action: PureInsertDocumentAction) { const { id, plugin: type, state: pluginState } = action.payload state[id] = { @@ -40,6 +51,7 @@ export const documentsSlice = createSlice({ }) export const { + insertAndFocusDocument, pureInsertDocument, pureRemoveDocument, pureChangeDocument, diff --git a/src/serlo-editor/store/documents/types.ts b/src/serlo-editor/store/documents/types.ts index fefdf8d72a..4ad6d143e0 100644 --- a/src/serlo-editor/store/documents/types.ts +++ b/src/serlo-editor/store/documents/types.ts @@ -2,6 +2,10 @@ import { PayloadAction } from '@reduxjs/toolkit' import type { DocumentState } from '../types' +export type InsertAndFocusDocumentAction = PayloadAction< + { id: string } & DocumentState +> + export type PureInsertDocumentAction = PayloadAction< { id: string } & DocumentState > From 7cab91c0c4cc8406e96795b0932b4a9a9c132001 Mon Sep 17 00:00:00 2001 From: Botho <1258870+elbotho@users.noreply.github.com> Date: Tue, 19 Sep 2023 13:03:30 +0200 Subject: [PATCH 3/6] autoFocus for all templates with a title --- src/serlo-editor/plugins/serlo-template-plugins/applet.tsx | 1 + src/serlo-editor/plugins/serlo-template-plugins/article.tsx | 1 + .../plugins/serlo-template-plugins/course/course-page.tsx | 1 + .../plugins/serlo-template-plugins/course/course.tsx | 1 + src/serlo-editor/plugins/serlo-template-plugins/event.tsx | 1 + src/serlo-editor/plugins/serlo-template-plugins/page.tsx | 1 + src/serlo-editor/plugins/serlo-template-plugins/taxonomy.tsx | 1 + src/serlo-editor/plugins/serlo-template-plugins/video.tsx | 1 + 8 files changed, 8 insertions(+) diff --git a/src/serlo-editor/plugins/serlo-template-plugins/applet.tsx b/src/serlo-editor/plugins/serlo-template-plugins/applet.tsx index 2afae0ba6b..b3f7c624b0 100644 --- a/src/serlo-editor/plugins/serlo-template-plugins/applet.tsx +++ b/src/serlo-editor/plugins/serlo-template-plugins/applet.tsx @@ -75,6 +75,7 @@ function AppletTypeEditor(props: EditorPluginProps) {

{props.editable ? ( ) {

{props.editable ? ( {props.editable ? ( ) { title={ props.editable ? ( ) {

{props.editable ? ( ) {

{props.editable ? ( ) {

{props.editable ? ( ) {

{props.editable ? ( Date: Tue, 19 Sep 2023 19:15:06 +0200 Subject: [PATCH 4/6] improve tab order --- src/serlo-editor/plugins/image/editor.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/serlo-editor/plugins/image/editor.tsx b/src/serlo-editor/plugins/image/editor.tsx index 3689c22f43..83f61364ba 100644 --- a/src/serlo-editor/plugins/image/editor.tsx +++ b/src/serlo-editor/plugins/image/editor.tsx @@ -60,6 +60,12 @@ export function ImageEditor(props: ImageProps) { /> ) : null} + {hasFocus && showInlineImageUrl ? ( +
+ +
+ ) : null} +
- - {hasFocus && showInlineImageUrl ? ( -
- -
- ) : null}
) From 79de334d58513f5558f828cf77e6644d0f387b1e Mon Sep 17 00:00:00 2001 From: Botho <1258870+elbotho@users.noreply.github.com> Date: Tue, 19 Sep 2023 19:30:35 +0200 Subject: [PATCH 5/6] manual focus useEffect in image plugin --- .../image/controls/inline-src-controls.tsx | 8 +++++- src/serlo-editor/plugins/image/editor.tsx | 27 ++++++++++++++----- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/serlo-editor/plugins/image/controls/inline-src-controls.tsx b/src/serlo-editor/plugins/image/controls/inline-src-controls.tsx index a2fe08fe02..bac3db8555 100644 --- a/src/serlo-editor/plugins/image/controls/inline-src-controls.tsx +++ b/src/serlo-editor/plugins/image/controls/inline-src-controls.tsx @@ -1,9 +1,14 @@ +import { RefObject } from 'react' + import type { ImageProps } from '..' import { useEditorStrings } from '@/contexts/logged-in-data-context' import { tw } from '@/helper/tw' import { isTempFile } from '@/serlo-editor/plugin' -export function InlineSrcControls({ state }: ImageProps) { +export function InlineSrcControls({ + state, + urlInputRef, +}: ImageProps & { urlInputRef: RefObject }) { const imageStrings = useEditorStrings().plugins.image const { src } = state @@ -18,6 +23,7 @@ export function InlineSrcControls({ state }: ImageProps) {