@atlaskit/editor-core
Version:
A package contains Atlassian editor core functionality
102 lines (85 loc) • 2.73 kB
text/typescript
import {
EditorState,
EditorView,
Schema,
MarkType,
Plugin,
PluginKey,
} from '../../prosemirror';
import { clearFormatting } from './commands';
import keymapPlugin from './keymap';
export type StateChangeHandler = (state: ClearFormattingState) => any;
export class ClearFormattingState {
formattingIsPresent: boolean = false;
private state: EditorState<any>;
private markTypes = [
'em', 'code', 'strike', 'strong', 'underline', 'link', 'textColor'
];
private activeMarkTypes: string[];
private changeHandlers: StateChangeHandler[] = [];
constructor(state: EditorState<any>) {
this.changeHandlers = [];
this.update(state);
}
subscribe(cb: StateChangeHandler) {
this.changeHandlers.push(cb);
cb(this);
}
unsubscribe(cb: StateChangeHandler) {
this.changeHandlers = this.changeHandlers.filter(ch => ch !== cb);
}
update(newEditorState: EditorState<any>) {
this.state = newEditorState;
const { state } = this;
this.activeMarkTypes = this.markTypes.filter(
mark => state.schema.marks[mark] && this.markIsActive(state.schema.marks[mark])
);
const formattingIsPresent = this.activeMarkTypes.length > 0 || this.blockStylingIsPresent();
if (formattingIsPresent !== this.formattingIsPresent) {
this.formattingIsPresent = formattingIsPresent;
this.triggerOnChange();
}
}
clearFormatting(view: EditorView) {
clearFormatting(this.markTypes)(view.state, view.dispatch);
}
private triggerOnChange() {
this.changeHandlers.forEach(cb => cb(this));
}
private markIsActive(mark: MarkType): boolean {
const { state } = this;
const { from, to, empty } = state.selection;
if (empty) {
return !!mark.isInSet(state.selection.$from.marks());
}
return state.doc.rangeHasMark(from, to, mark);
}
private blockStylingIsPresent = (): boolean => {
const { state } = this;
let { from, to } = state.selection;
let isBlockStyling = false;
state.doc.nodesBetween(from, to, (node, pos) => {
if (node.isBlock && node.type !== state.schema.nodes.paragraph) {
isBlockStyling = true;
}
});
return isBlockStyling;
}
}
export const stateKey = new PluginKey('clearFormattingPlugin');
export const plugin = new Plugin({
state: {
init(config, state: EditorState<any>) {
return new ClearFormattingState(state);
},
apply(tr, pluginState: ClearFormattingState, oldState, newState) {
pluginState.update(newState);
return pluginState;
}
},
key: stateKey
});
const plugins = (schema: Schema<any, any>) => {
return [plugin, keymapPlugin(schema)].filter((plugin) => !!plugin) as Plugin[];
};
export default plugins;