feat: Initial clean release of CHM
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
这个提交包含在:
@@ -0,0 +1,126 @@
|
||||
import { Command, EditorState, Plugin } from 'prosemirror-state';
|
||||
import { EditorView } from 'prosemirror-view';
|
||||
import { Node } from 'prosemirror-model';
|
||||
|
||||
// See the fold example for more information about
|
||||
// writing similar ProseMirror plugins:
|
||||
// https://prosemirror.net/examples/fold/
|
||||
|
||||
type EditRequest = {
|
||||
nodeStart: number;
|
||||
showEditor: true;
|
||||
} | {
|
||||
nodeStart?: undefined;
|
||||
showEditor: false;
|
||||
};
|
||||
|
||||
interface PluginState {
|
||||
editingNodeAt: number|null;
|
||||
}
|
||||
|
||||
interface EditorDialog {
|
||||
onPositionChange: (position: number)=> void;
|
||||
dismiss: ()=> void;
|
||||
}
|
||||
|
||||
export type OnHide = ()=> void;
|
||||
interface Options {
|
||||
canEdit: (node: Node, pos: number)=> boolean;
|
||||
showEditor: (pos: number, view: EditorView, onHide: OnHide)=> EditorDialog;
|
||||
}
|
||||
|
||||
const createExternalEditorPlugin = (options: Options) => {
|
||||
const plugin = new Plugin<PluginState>({
|
||||
state: {
|
||||
init: () => ({
|
||||
editingNodeAt: null,
|
||||
}),
|
||||
apply: (tr, oldValue) => {
|
||||
let editingAt = oldValue.editingNodeAt;
|
||||
|
||||
const editRequest: EditRequest|null = tr.getMeta(plugin);
|
||||
if (editRequest) {
|
||||
if (editRequest.showEditor) {
|
||||
editingAt = editRequest.nodeStart;
|
||||
} else {
|
||||
editingAt = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (editingAt) {
|
||||
editingAt = tr.mapping.map(editingAt, 1);
|
||||
}
|
||||
return { editingNodeAt: editingAt };
|
||||
},
|
||||
},
|
||||
view: () => {
|
||||
let dialog: EditorDialog|null = null;
|
||||
|
||||
return {
|
||||
update(view, prevState) {
|
||||
const oldState = plugin.getState(prevState);
|
||||
const newState = plugin.getState(view.state);
|
||||
|
||||
if (newState.editingNodeAt !== null) {
|
||||
if (oldState.editingNodeAt === null) {
|
||||
const onHide = () => {
|
||||
hideEditor(view.state, view.dispatch, view);
|
||||
};
|
||||
dialog = options.showEditor(newState.editingNodeAt, view, onHide);
|
||||
}
|
||||
dialog?.onPositionChange(newState.editingNodeAt);
|
||||
} else if (dialog) {
|
||||
const lastDialog = dialog;
|
||||
// Set dialog to null before dismissing to prevent infinite recursion.
|
||||
// Dismissing the dialog can cause the editor state to update, which can
|
||||
// result in this callback being re-run.
|
||||
dialog = null;
|
||||
|
||||
lastDialog.dismiss();
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const editAt = (nodeStart: number): Command => (state, dispatch) => {
|
||||
const node = state.doc.nodeAt(nodeStart);
|
||||
if (!options.canEdit(node, nodeStart)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dispatch) {
|
||||
const editRequest: EditRequest = {
|
||||
nodeStart,
|
||||
showEditor: true,
|
||||
};
|
||||
dispatch(state.tr.setMeta(plugin, editRequest));
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const isEditorVisible = (state: EditorState) => {
|
||||
return plugin.getState(state).editingNodeAt !== null;
|
||||
};
|
||||
|
||||
const hideEditor: Command = (state, dispatch) => {
|
||||
const isEditing = isEditorVisible(state);
|
||||
if (!isEditing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dispatch) {
|
||||
const editRequest: EditRequest = {
|
||||
showEditor: false,
|
||||
};
|
||||
dispatch(state.tr.setMeta(plugin, editRequest));
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
return { plugin, hideEditor, editAt, isEditorVisible };
|
||||
};
|
||||
|
||||
export default createExternalEditorPlugin;
|
||||
在新工单中引用
屏蔽一个用户