From fcdc39b5495fa6c93edfca453474bd484e8cb44e Mon Sep 17 00:00:00 2001
From: Sibiraj <20282546+sibiraj-s@users.noreply.github.com>
Date: Fri, 8 May 2020 20:49:32 +0530
Subject: [PATCH] feat: add support for custom plugins
---
demo/src/app/app.component.html | 2 +-
demo/src/app/app.component.ts | 1 -
demo/src/app/app.module.ts | 8 ++-
.../plugins.ts => demo/src/app/plugin.ts | 41 ++++++-----
src/lib/ngx-editor.component.ts | 23 +++---
src/lib/ngx-editor.module.ts | 27 ++++++-
src/lib/ngx-editor.service.ts | 31 ++++++++
src/lib/plugins/menu/i18n.ts | 8 ---
src/lib/plugins/menu/index.ts | 20 ------
src/lib/prosemirror/commands/index.ts | 2 +
.../commands/toggleBlockType.ts | 4 +-
.../commands/toggleList.ts | 4 +-
src/lib/prosemirror/helpers/index.ts | 2 +
.../helpers/isMarkActive.ts | 2 +-
.../helpers/isNodeActive.ts | 2 +-
src/lib/prosemirror/plugins/index.ts | 2 +
.../plugins/menu/MenuBarView.ts | 10 +--
src/lib/prosemirror/plugins/menu/index.ts | 41 +++++++++++
.../{ => prosemirror}/plugins/menu/menu.ts | 42 ++++++-----
.../{ => prosemirror}/plugins/menu/meta.ts | 21 +++++-
.../{ => prosemirror}/plugins/placeholder.ts | 4 +-
src/lib/types.ts | 28 +++-----
src/lib/utils/computeOptions.ts | 49 -------------
src/ng-package.json | 4 --
src/package.json | 4 --
src/public-api.ts | 4 ++
wiki/content/configuartion.md | 51 ++++++-------
wiki/content/examples.md | 72 +++++++++++++++++++
wiki/content/shortcuts.md | 12 ----
wiki/summary.json | 4 +-
30 files changed, 312 insertions(+), 213 deletions(-)
rename src/lib/utils/plugins.ts => demo/src/app/plugin.ts (62%)
create mode 100644 src/lib/ngx-editor.service.ts
delete mode 100644 src/lib/plugins/menu/i18n.ts
delete mode 100644 src/lib/plugins/menu/index.ts
create mode 100644 src/lib/prosemirror/commands/index.ts
rename src/lib/{pm-tools => prosemirror}/commands/toggleBlockType.ts (83%)
rename src/lib/{pm-tools => prosemirror}/commands/toggleList.ts (86%)
create mode 100644 src/lib/prosemirror/helpers/index.ts
rename src/lib/{pm-tools => prosemirror}/helpers/isMarkActive.ts (80%)
rename src/lib/{pm-tools => prosemirror}/helpers/isNodeActive.ts (87%)
create mode 100644 src/lib/prosemirror/plugins/index.ts
rename src/lib/{ => prosemirror}/plugins/menu/MenuBarView.ts (75%)
create mode 100644 src/lib/prosemirror/plugins/menu/index.ts
rename src/lib/{ => prosemirror}/plugins/menu/menu.ts (91%)
rename src/lib/{ => prosemirror}/plugins/menu/meta.ts (70%)
rename src/lib/{ => prosemirror}/plugins/placeholder.ts (87%)
delete mode 100644 src/lib/utils/computeOptions.ts
create mode 100644 wiki/content/examples.md
delete mode 100644 wiki/content/shortcuts.md
diff --git a/demo/src/app/app.component.html b/demo/src/app/app.component.html
index 0daa7f29..89766a05 100644
--- a/demo/src/app/app.component.html
+++ b/demo/src/app/app.component.html
@@ -13,7 +13,7 @@
-
+
diff --git a/demo/src/app/app.component.ts b/demo/src/app/app.component.ts
index e45142a1..041bda71 100644
--- a/demo/src/app/app.component.ts
+++ b/demo/src/app/app.component.ts
@@ -8,7 +8,6 @@ import { environment } from '../environments/environment';
})
export class AppComponent {
- placeholder = 'Type something here...';
isProdMode = environment.production;
editorContent: object = {
diff --git a/demo/src/app/app.module.ts b/demo/src/app/app.module.ts
index 843e2a9f..2da10f16 100644
--- a/demo/src/app/app.module.ts
+++ b/demo/src/app/app.module.ts
@@ -1,3 +1,4 @@
+import { CommonModule } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
@@ -5,14 +6,19 @@ import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { NgxEditorModule } from 'ngx-editor';
+import { getPlugins } from './plugin';
+
@NgModule({
declarations: [
AppComponent
],
imports: [
+ CommonModule,
BrowserModule,
FormsModule,
- NgxEditorModule,
+ NgxEditorModule.forRoot({
+ plugins: getPlugins()
+ }),
],
bootstrap: [AppComponent]
})
diff --git a/src/lib/utils/plugins.ts b/demo/src/app/plugin.ts
similarity index 62%
rename from src/lib/utils/plugins.ts
rename to demo/src/app/plugin.ts
index 01014d07..8efe91a0 100644
--- a/src/lib/utils/plugins.ts
+++ b/demo/src/app/plugin.ts
@@ -1,18 +1,15 @@
-import { Plugin } from 'prosemirror-state';
-import { history, undo, redo } from 'prosemirror-history';
-import { keymap } from 'prosemirror-keymap';
-import { baseKeymap, toggleMark } from 'prosemirror-commands';
-
-import schema from '../schema';
+import { schema, menu, placeholder } from 'ngx-editor';
-import { ComputedOptions, KeyMap } from '../types';
-
-import menu from '../plugins/menu';
-import placeholder from '../plugins/placeholder';
+import { undo, redo, history } from 'prosemirror-history';
import { splitListItem, liftListItem, sinkListItem } from 'prosemirror-schema-list';
+import { keymap } from 'prosemirror-keymap';
+import { toggleMark, baseKeymap } from 'prosemirror-commands';
+import { Plugin } from 'prosemirror-state';
const isMacOs = /Mac/.test(navigator.platform);
+export type KeyMap = { [key: string]: any };
+
const getHistoryKeyMap = (): KeyMap => {
const historyMap: KeyMap = {};
@@ -38,7 +35,7 @@ const getListKeyMap = (): KeyMap => {
return listMap;
};
-export const getPlugins = (options: ComputedOptions): Plugin[] => {
+export const getPlugins = (): Plugin[] => {
const historyKeyMap = getHistoryKeyMap();
const listKeyMap = getListKeyMap();
@@ -52,12 +49,24 @@ export const getPlugins = (options: ComputedOptions): Plugin[] => {
keymap(historyKeyMap),
keymap(listKeyMap),
keymap(baseKeymap),
- placeholder(options.placeholder),
+ menu({
+ toolbar: [
+ ['bold', 'italic'],
+ ['code'],
+ ['ordered_list', 'bullet_list'],
+ [{ heading: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] }]
+ ],
+ labels: {
+ bold: 'Bold',
+ italics: 'Italics',
+ code: 'Code',
+ ordered_list: 'Ordered List',
+ bullet_list: 'Bullet List',
+ heading: 'Header'
+ }
+ }),
+ placeholder('Type Something here...')
];
- if (options.toolbar) {
- plugins.push(menu(options.toolbar));
- }
-
return plugins;
};
diff --git a/src/lib/ngx-editor.component.ts b/src/lib/ngx-editor.component.ts
index 7223772c..db6b397a 100644
--- a/src/lib/ngx-editor.component.ts
+++ b/src/lib/ngx-editor.component.ts
@@ -8,12 +8,9 @@ import { EditorState, Transaction } from 'prosemirror-state';
import { EditorView } from 'prosemirror-view';
import { Node as ProsemirrorNode } from 'prosemirror-model';
-import schema from './schema';
-
-import { Config, ComputedOptions } from './types';
+import { NgxEditorService, NgxEditorServiceConfig } from './ngx-editor.service';
-import { getPlugins } from './utils/plugins';
-import computeOptions from './utils/computeOptions';
+import schema from './schema';
@Component({
selector: 'ngx-editor',
@@ -30,13 +27,14 @@ import computeOptions from './utils/computeOptions';
export class NgxEditorComponent implements ControlValueAccessor, OnInit, OnDestroy {
@ViewChild('ngxEditor', { static: true }) ngxEditor: ElementRef;
- @Input() placeholder = 'Type here...';
- @Input() config: Config;
-
private view: EditorView;
private onChange: (value: object) => void;
- private options: ComputedOptions;
+ private config: NgxEditorServiceConfig;
+
+ constructor(ngxEditorService: NgxEditorService) {
+ this.config = ngxEditorService.config;
+ }
writeValue(value: object | null) {
if (!value) {
@@ -84,7 +82,7 @@ export class NgxEditorComponent implements ControlValueAccessor, OnInit, OnDestr
this.view = new EditorView(this.ngxEditor.nativeElement, {
state: EditorState.create({
schema,
- plugins: getPlugins(this.options),
+ plugins: this.config.plugins,
}),
dispatchTransaction: this.handleTransactions.bind(this),
attributes: {
@@ -94,11 +92,6 @@ export class NgxEditorComponent implements ControlValueAccessor, OnInit, OnDestr
}
ngOnInit() {
- this.options = computeOptions({
- placeholder: this.placeholder,
- config: this.config
- });
-
this.createEditor();
}
diff --git a/src/lib/ngx-editor.module.ts b/src/lib/ngx-editor.module.ts
index f60a494c..83bd7c17 100644
--- a/src/lib/ngx-editor.module.ts
+++ b/src/lib/ngx-editor.module.ts
@@ -1,10 +1,33 @@
-import { NgModule } from '@angular/core';
+import { NgModule, ModuleWithProviders, InjectionToken } from '@angular/core';
import { NgxEditorComponent } from './ngx-editor.component';
+import { NgxEditorServiceConfig, provideMyServiceOptions } from './ngx-editor.service';
+import { NgxEditorConfig } from './types';
+
+const NGX_EDITOR_CONFIG_TOKEN = new InjectionToken('NgxEditorConfig');
+
@NgModule({
declarations: [NgxEditorComponent],
exports: [NgxEditorComponent],
})
-export class NgxEditorModule { }
+export class NgxEditorModule {
+ static forRoot(config: NgxEditorConfig): ModuleWithProviders {
+
+ return {
+ ngModule: NgxEditorModule,
+ providers: [
+ {
+ provide: NGX_EDITOR_CONFIG_TOKEN,
+ useValue: config
+ },
+ {
+ provide: NgxEditorServiceConfig,
+ useFactory: provideMyServiceOptions,
+ deps: [NGX_EDITOR_CONFIG_TOKEN]
+ }
+ ]
+ };
+ }
+}
diff --git a/src/lib/ngx-editor.service.ts b/src/lib/ngx-editor.service.ts
new file mode 100644
index 00000000..ab1d2996
--- /dev/null
+++ b/src/lib/ngx-editor.service.ts
@@ -0,0 +1,31 @@
+import { Injectable, Optional } from '@angular/core';
+
+import { NgxEditorConfig } from './types';
+
+import menu from './prosemirror/plugins/menu';
+import placeholder from './prosemirror/plugins/placeholder';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class NgxEditorServiceConfig {
+ public plugins = [
+ menu(),
+ placeholder()
+ ];
+}
+
+@Injectable({
+ providedIn: 'root'
+})
+export class NgxEditorService {
+ config: NgxEditorServiceConfig;
+
+ constructor(@Optional() config?: NgxEditorServiceConfig) {
+ this.config = config;
+ }
+}
+
+export function provideMyServiceOptions(config?: NgxEditorConfig): NgxEditorConfig {
+ return (config);
+}
diff --git a/src/lib/plugins/menu/i18n.ts b/src/lib/plugins/menu/i18n.ts
deleted file mode 100644
index 4dd1763f..00000000
--- a/src/lib/plugins/menu/i18n.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export const labels = {
- bold: 'Bold',
- italics: 'Italics',
- code: 'Code',
- ordered_list: 'Ordered List',
- bullet_list: 'Bullet List',
- heading: 'Heading'
-};
diff --git a/src/lib/plugins/menu/index.ts b/src/lib/plugins/menu/index.ts
deleted file mode 100644
index a19b9b4d..00000000
--- a/src/lib/plugins/menu/index.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { EditorView } from 'prosemirror-view';
-import { Plugin, PluginKey } from 'prosemirror-state';
-
-import { Toolbar } from '../../types';
-import MenuBarView from './MenuBarView';
-
-function menuPlugin(toolbar: Toolbar): Plugin {
- return new Plugin({
- key: new PluginKey('menu'),
- view(editorView: EditorView): MenuBarView {
- return new MenuBarView(toolbar, editorView);
- },
- });
-}
-
-const menu = (toolbarOptions: Toolbar) => {
- return menuPlugin(toolbarOptions);
-};
-
-export default menu;
diff --git a/src/lib/prosemirror/commands/index.ts b/src/lib/prosemirror/commands/index.ts
new file mode 100644
index 00000000..d572f7a4
--- /dev/null
+++ b/src/lib/prosemirror/commands/index.ts
@@ -0,0 +1,2 @@
+export * from './toggleBlockType';
+export * from './toggleList';
diff --git a/src/lib/pm-tools/commands/toggleBlockType.ts b/src/lib/prosemirror/commands/toggleBlockType.ts
similarity index 83%
rename from src/lib/pm-tools/commands/toggleBlockType.ts
rename to src/lib/prosemirror/commands/toggleBlockType.ts
index 03f6eef4..eb464f93 100644
--- a/src/lib/pm-tools/commands/toggleBlockType.ts
+++ b/src/lib/prosemirror/commands/toggleBlockType.ts
@@ -4,7 +4,7 @@ import { setBlockType } from 'prosemirror-commands';
import isNodeActive from '../helpers/isNodeActive';
-export default function toggleBlockType(type: NodeType, toggleType: NodeType, attrs = {}) {
+export const toggleBlockType = (type: NodeType, toggleType: NodeType, attrs = {}) => {
return (state: EditorState, dispatch: (tr: Transaction) => void) => {
const isActive = isNodeActive(state, type, attrs);
@@ -14,4 +14,4 @@ export default function toggleBlockType(type: NodeType, toggleType: NodeType, at
return setBlockType(type, attrs)(state, dispatch);
};
-}
+};
diff --git a/src/lib/pm-tools/commands/toggleList.ts b/src/lib/prosemirror/commands/toggleList.ts
similarity index 86%
rename from src/lib/pm-tools/commands/toggleList.ts
rename to src/lib/prosemirror/commands/toggleList.ts
index 4db4aeda..73c5f8dd 100644
--- a/src/lib/pm-tools/commands/toggleList.ts
+++ b/src/lib/prosemirror/commands/toggleList.ts
@@ -4,7 +4,7 @@ import { wrapInList, liftListItem } from 'prosemirror-schema-list';
import isNodeActive from '../helpers/isNodeActive';
-export default function toggleList(type: NodeType, itemType: NodeType) {
+export const toggleList = (type: NodeType, itemType: NodeType) => {
return (state: EditorState, dispatch: (tr: Transaction) => void) => {
const isActive = isNodeActive(state, type);
@@ -14,4 +14,4 @@ export default function toggleList(type: NodeType, itemType: NodeType) {
return wrapInList(type)(state, dispatch);
};
-}
+};
diff --git a/src/lib/prosemirror/helpers/index.ts b/src/lib/prosemirror/helpers/index.ts
new file mode 100644
index 00000000..54ea7b32
--- /dev/null
+++ b/src/lib/prosemirror/helpers/index.ts
@@ -0,0 +1,2 @@
+export * from './isMarkActive';
+export * from './isNodeActive';
diff --git a/src/lib/pm-tools/helpers/isMarkActive.ts b/src/lib/prosemirror/helpers/isMarkActive.ts
similarity index 80%
rename from src/lib/pm-tools/helpers/isMarkActive.ts
rename to src/lib/prosemirror/helpers/isMarkActive.ts
index 237952aa..a61fb97d 100644
--- a/src/lib/pm-tools/helpers/isMarkActive.ts
+++ b/src/lib/prosemirror/helpers/isMarkActive.ts
@@ -1,7 +1,7 @@
import { EditorState } from 'prosemirror-state';
import { MarkType } from 'prosemirror-model';
-const isMarkActive = (state: EditorState, type: MarkType): boolean => {
+export const isMarkActive = (state: EditorState, type: MarkType): boolean => {
const { from, $from, to, empty } = state.selection;
if (empty) {
diff --git a/src/lib/pm-tools/helpers/isNodeActive.ts b/src/lib/prosemirror/helpers/isNodeActive.ts
similarity index 87%
rename from src/lib/pm-tools/helpers/isNodeActive.ts
rename to src/lib/prosemirror/helpers/isNodeActive.ts
index 1e7433d1..fc855a37 100644
--- a/src/lib/pm-tools/helpers/isNodeActive.ts
+++ b/src/lib/prosemirror/helpers/isNodeActive.ts
@@ -2,7 +2,7 @@ import { EditorState } from 'prosemirror-state';
import { NodeType, Node as ProsemirrorNode } from 'prosemirror-model';
import { findSelectedNodeOfType, findParentNode } from 'prosemirror-utils';
-const isNodeActive = (state: EditorState, type: NodeType, attrs = {}): boolean => {
+export const isNodeActive = (state: EditorState, type: NodeType, attrs = {}): boolean => {
const { $from, to } = state.selection;
const predicate = (n: ProsemirrorNode) => n.type === type;
diff --git a/src/lib/prosemirror/plugins/index.ts b/src/lib/prosemirror/plugins/index.ts
new file mode 100644
index 00000000..2135df8d
--- /dev/null
+++ b/src/lib/prosemirror/plugins/index.ts
@@ -0,0 +1,2 @@
+export { default as placeholder } from './placeholder';
+export { default as menu } from './menu';
diff --git a/src/lib/plugins/menu/MenuBarView.ts b/src/lib/prosemirror/plugins/menu/MenuBarView.ts
similarity index 75%
rename from src/lib/plugins/menu/MenuBarView.ts
rename to src/lib/prosemirror/plugins/menu/MenuBarView.ts
index 455d0c9b..ef3dc6bb 100644
--- a/src/lib/plugins/menu/MenuBarView.ts
+++ b/src/lib/prosemirror/plugins/menu/MenuBarView.ts
@@ -1,22 +1,22 @@
import { EditorView } from 'prosemirror-view';
import { EditorState } from 'prosemirror-state';
-import { Toolbar } from '../../types';
+import { MenuOptions } from '../../../types';
import { renderMenu } from './menu';
class MenuBarView {
- toolbar: Toolbar;
+ options: MenuOptions;
view: EditorView;
dom: HTMLElement;
updateMenuItems: (state: EditorState) => void;
- constructor(toolbar: Toolbar, editorView: EditorView) {
+ constructor(editorView: EditorView, options: MenuOptions) {
// const menu = getMenu(toolbar);
this.view = editorView;
- this.toolbar = toolbar;
+ this.options = options;
this.render();
this.update();
@@ -26,7 +26,7 @@ class MenuBarView {
const menuDom = document.createElement('div');
menuDom.className = 'NgxEditor-MenuBar';
- const { update } = renderMenu(this.toolbar, this.view, menuDom);
+ const { update } = renderMenu(this.options, this.view, menuDom);
this.updateMenuItems = update;
this.view.dom.parentNode.insertBefore(menuDom, this.view.dom);
diff --git a/src/lib/prosemirror/plugins/menu/index.ts b/src/lib/prosemirror/plugins/menu/index.ts
new file mode 100644
index 00000000..96156d15
--- /dev/null
+++ b/src/lib/prosemirror/plugins/menu/index.ts
@@ -0,0 +1,41 @@
+import { EditorView } from 'prosemirror-view';
+import { Plugin, PluginKey } from 'prosemirror-state';
+
+import { Toolbar, MenuLabels, MenuOptions } from '../../../types';
+import MenuBarView from './MenuBarView';
+
+const DEFAULT_TOOLBAR: Toolbar = [
+ ['bold', 'italic'],
+ ['code'],
+ ['ordered_list', 'bullet_list'],
+ [{ heading: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] }]
+];
+
+const DEFAULT_LABELS: MenuLabels = {
+ bold: 'Bold',
+ italics: 'Italics',
+ code: 'Code',
+ ordered_list: 'Ordered List',
+ bullet_list: 'Bullet List',
+ heading: 'Heading'
+};
+
+const DEFAULT_OPTIONS: MenuOptions = {
+ toolbar: DEFAULT_TOOLBAR,
+ labels: DEFAULT_LABELS
+};
+
+function menuPlugin(options: MenuOptions): Plugin {
+ return new Plugin({
+ key: new PluginKey('menu'),
+ view(editorView: EditorView): MenuBarView {
+ return new MenuBarView(editorView, options);
+ },
+ });
+}
+
+const menu = (options: MenuOptions = DEFAULT_OPTIONS) => {
+ return menuPlugin(options);
+};
+
+export default menu;
diff --git a/src/lib/plugins/menu/menu.ts b/src/lib/prosemirror/plugins/menu/menu.ts
similarity index 91%
rename from src/lib/plugins/menu/menu.ts
rename to src/lib/prosemirror/plugins/menu/menu.ts
index a41d6cc8..6ab4c5b3 100644
--- a/src/lib/plugins/menu/menu.ts
+++ b/src/lib/prosemirror/plugins/menu/menu.ts
@@ -4,27 +4,23 @@ import { EditorState } from 'prosemirror-state';
import { MarkType, NodeType } from 'prosemirror-model';
import {
- Toolbar,
- MenuItemMeta,
MenuItemViewSpec,
ToolbarItem,
ToolbarDropdownGroupKeys,
- ToolbarDropdownGroupValues
-} from '../../types';
+ ToolbarDropdownGroupValues,
+ MenuOptions
+} from '../../../types';
-import schema from '../../schema';
+import schema from '../../../schema';
-import isNodeActive from '../../pm-tools/helpers/isNodeActive';
-import isMarkActive from '../../pm-tools/helpers/isMarkActive';
-import toggleList from '../../pm-tools/commands/toggleList';
-import toggleBlockType from '../../pm-tools/commands/toggleBlockType';
+import isNodeActive from '../../helpers/isNodeActive';
+import isMarkActive from '../../helpers/isMarkActive';
+import { toggleList, toggleBlockType } from '../../commands';
-import { getIconSvg } from '../../utils/icons';
-import flatDeep from '../../utils/flatDeep';
+import { getIconSvg } from '../../../utils/icons';
+import flatDeep from '../../../utils/flatDeep';
-import menuItemsMeta from './meta';
-
-import { labels } from './i18n';
+import menuItemsMeta, {MenuItemMeta} from './meta';
const MENU_ITEM_CLASSNAME = 'NgxEditor-MenuItem';
@@ -43,6 +39,8 @@ class DropDownView {
private dropdownGroup: ToolbarDropdownGroupKeys;
private dropdownFields: ToolbarDropdownGroupValues;
private editorView: EditorView;
+ private options: MenuOptions;
+
dom: HTMLElement;
updates = [];
@@ -50,17 +48,21 @@ class DropDownView {
constructor(
dropdownGroup: ToolbarDropdownGroupKeys,
dropdownFields: ToolbarDropdownGroupValues,
- editorView: EditorView
+ editorView: EditorView,
+ options: MenuOptions
) {
this.dropdownGroup = dropdownGroup;
this.dropdownFields = dropdownFields;
this.editorView = editorView;
+ this.options = options;
}
getWrapperDom(): HTMLElement {
let isDropdownOpen = false;
const dropdownWrapper = document.createElement('div');
+ const labels = this.options.labels;
+
dropdownWrapper.classList.add(MENU_ITEM_CLASSNAME);
dropdownWrapper.classList.add(`${MENU_ITEM_CLASSNAME}__Dropdown-Wrapper`);
@@ -286,9 +288,11 @@ const getSeperatorDom = (): HTMLElement => {
return div;
};
-export const renderMenu = (toolbar: Toolbar, editorView: EditorView, menuDom: HTMLElement) => {
+export const renderMenu = (options: MenuOptions, editorView: EditorView, menuDom: HTMLElement) => {
const updates: any[] = [];
+ const toolbar = options.toolbar;
+
toolbar.forEach((group: ToolbarItem[], toolbarIndex: number): void => {
const isLastMenuGroup = toolbar.length - 1 === toolbarIndex;
@@ -301,7 +305,7 @@ export const renderMenu = (toolbar: Toolbar, editorView: EditorView, menuDom: HT
if (DROPDOWN_ITEMS.has(dropdownGroup)) {
const dropdown: ToolbarDropdownGroupValues = toolbarItem[dropdownGroup];
- const dropdownView = new DropDownView(dropdownGroup, dropdown, editorView);
+ const dropdownView = new DropDownView(dropdownGroup, dropdown, editorView, options);
const rendered = dropdownView.render();
updates.push(rendered.updates);
menuDom.appendChild(rendered.dom);
@@ -315,6 +319,8 @@ export const renderMenu = (toolbar: Toolbar, editorView: EditorView, menuDom: HT
if (typeof toolbarItem === 'string') {
const menuItem = menuItemsMeta[toolbarItem];
+ const labels = options.labels;
+
if (menuItem) {
const spec: MenuItemViewSpec = {
classNames: [
@@ -324,7 +330,7 @@ export const renderMenu = (toolbar: Toolbar, editorView: EditorView, menuDom: HT
],
innerHTML: getIconSvg(menuItem.icon),
attrs: {
- title: menuItem.key
+ title: labels[menuItem.i18nKey]
}
};
diff --git a/src/lib/plugins/menu/meta.ts b/src/lib/prosemirror/plugins/menu/meta.ts
similarity index 70%
rename from src/lib/plugins/menu/meta.ts
rename to src/lib/prosemirror/plugins/menu/meta.ts
index ee60ea47..fc5c5aac 100644
--- a/src/lib/plugins/menu/meta.ts
+++ b/src/lib/prosemirror/plugins/menu/meta.ts
@@ -1,33 +1,47 @@
-import { MenuItemMeta } from '../../types';
+export interface MenuItemMeta {
+ key: string;
+ i18nKey: string;
+ icon?: string;
+ type: 'mark' | 'node';
+ attrs?: {
+ level?: number
+ };
+}
const menuItemsMeta: { [key: string]: MenuItemMeta } = {
bold: {
key: 'strong',
+ i18nKey: 'bold',
icon: 'bold',
type: 'mark',
},
italic: {
key: 'em',
+ i18nKey: 'italics',
icon: 'italic',
type: 'mark',
},
code: {
key: 'code',
+ i18nKey: 'code',
icon: 'code',
type: 'mark',
},
ordered_list: {
key: 'ordered_list',
+ i18nKey: 'ordered_list',
icon: 'ordered_list',
type: 'node',
},
bullet_list: {
key: 'bullet_list',
+ i18nKey: 'bullet_list',
icon: 'bullet_list',
type: 'node',
},
h1: {
key: 'heading',
+ i18nKey: 'heading',
attrs: {
level: 1,
},
@@ -35,6 +49,7 @@ const menuItemsMeta: { [key: string]: MenuItemMeta } = {
},
h2: {
key: 'heading',
+ i18nKey: 'heading',
attrs: {
level: 2,
},
@@ -42,6 +57,7 @@ const menuItemsMeta: { [key: string]: MenuItemMeta } = {
},
h3: {
key: 'heading',
+ i18nKey: 'heading',
attrs: {
level: 3,
},
@@ -49,6 +65,7 @@ const menuItemsMeta: { [key: string]: MenuItemMeta } = {
},
h4: {
key: 'heading',
+ i18nKey: 'heading',
attrs: {
level: 4,
},
@@ -56,6 +73,7 @@ const menuItemsMeta: { [key: string]: MenuItemMeta } = {
},
h5: {
key: 'heading',
+ i18nKey: 'heading',
attrs: {
level: 5,
},
@@ -63,6 +81,7 @@ const menuItemsMeta: { [key: string]: MenuItemMeta } = {
},
h6: {
key: 'heading',
+ i18nKey: 'heading',
attrs: {
level: 6,
},
diff --git a/src/lib/plugins/placeholder.ts b/src/lib/prosemirror/plugins/placeholder.ts
similarity index 87%
rename from src/lib/plugins/placeholder.ts
rename to src/lib/prosemirror/plugins/placeholder.ts
index 645c409c..08e385e9 100644
--- a/src/lib/plugins/placeholder.ts
+++ b/src/lib/prosemirror/plugins/placeholder.ts
@@ -1,7 +1,9 @@
import { Plugin, EditorState, PluginKey } from 'prosemirror-state';
import { DecorationSet, Decoration } from 'prosemirror-view';
-function placeholderPlugin(text: string) {
+const DEFAULT_PLACEHOLDER = 'Type Here...';
+
+function placeholderPlugin(text: string = DEFAULT_PLACEHOLDER) {
return new Plugin({
key: new PluginKey('placeholder'),
props: {
diff --git a/src/lib/types.ts b/src/lib/types.ts
index e6c94dcb..26ef5d06 100644
--- a/src/lib/types.ts
+++ b/src/lib/types.ts
@@ -1,24 +1,11 @@
+import { Plugin } from 'prosemirror-state';
+
export type ToolbarDropdown = { heading?: string[] };
export type ToolbarDropdownGroupKeys = keyof ToolbarDropdown;
export type ToolbarDropdownGroupValues = ToolbarDropdown[ToolbarDropdownGroupKeys];
export type ToolbarItem = string | ToolbarDropdown;
export type Toolbar = Array | null;
-export interface Config {
- toolbar: boolean | Toolbar;
-}
-
-export interface MenuItemMeta {
- key: string;
- icon?: string;
- type: 'mark' | 'node';
- label?: string;
- attrs?: {
- level?: number
- };
- command?: any;
-}
-
export interface MenuItemViewSpec {
classNames?: string[];
innerHTML?: string;
@@ -26,9 +13,12 @@ export interface MenuItemViewSpec {
attrs?: { [key: string]: string };
}
-export interface ComputedOptions extends Config {
- placeholder: string;
- toolbar: Toolbar;
+export interface NgxEditorConfig {
+ plugins: Plugin[];
}
-export type KeyMap = { [key: string]: any };
+export type MenuLabels = { [key: string]: string };
+export interface MenuOptions {
+ toolbar?: Toolbar;
+ labels?: MenuLabels;
+}
diff --git a/src/lib/utils/computeOptions.ts b/src/lib/utils/computeOptions.ts
deleted file mode 100644
index 9763c7ab..00000000
--- a/src/lib/utils/computeOptions.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import { ComputedOptions, Config, Toolbar } from '../types';
-
-interface Options {
- placeholder: string;
- config: Config;
-}
-
-const defaultToolbarOptions: Toolbar = [
- ['bold', 'italic'],
- ['code'],
- ['ordered_list', 'bullet_list'],
- [{ heading: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] }]
-];
-
-const defaultConfig: Config = {
- toolbar: true
-};
-
-const getToolbar = (config: Config): Toolbar => {
- let toolbar = null;
-
- // set toolbar options
- if (typeof config.toolbar === 'boolean') {
- if (config.toolbar) {
- toolbar = defaultToolbarOptions;
- }
- } else {
- toolbar = config.toolbar;
- }
-
- return toolbar;
-};
-
-// prefer attributes to config
-const computeOptions = (options: Options): ComputedOptions => {
- const computedOptions = {} as ComputedOptions;
-
- const config = Object.assign({}, defaultConfig, options.config);
-
- computedOptions.toolbar = getToolbar(config);
-
- if (options.placeholder) {
- computedOptions.placeholder = options.placeholder;
- }
-
- return computedOptions;
-};
-
-export default computeOptions;
diff --git a/src/ng-package.json b/src/ng-package.json
index d9259b48..5b16347a 100644
--- a/src/ng-package.json
+++ b/src/ng-package.json
@@ -9,8 +9,6 @@
"prosemirror-model": "prosemirrorModel",
"prosemirror-schema-basic": "prosemirrorSchemaBasic",
"prosemirror-schema-list": "prosemirrorSchemaList",
- "prosemirror-history": "prosemirrorHistory",
- "prosemirror-keymap": "prosemirrorKeymap",
"prosemirror-commands": "prosemirrorCommands",
"prosemirror-utils": "prosemirrorUtils"
}
@@ -21,8 +19,6 @@
"prosemirror-model",
"prosemirror-schema-basic",
"prosemirror-schema-list",
- "prosemirror-history",
- "prosemirror-keymap",
"prosemirror-commands",
"prosemirror-utils",
"prosemirror-tables"
diff --git a/src/package.json b/src/package.json
index 3391c2e0..08408b85 100644
--- a/src/package.json
+++ b/src/package.json
@@ -21,16 +21,12 @@
},
"dependencies": {
"prosemirror-commands": "^1.1.0",
- "prosemirror-history": "^1.1.0",
- "prosemirror-keymap": "^1.1.0",
"prosemirror-model": "^1.1.0",
"prosemirror-schema-basic": "^1.1.0",
"prosemirror-schema-list": "^1.1.0",
"prosemirror-state": "^1.3.0",
"prosemirror-tables": "^1.1.0",
-
"prosemirror-utils": "^0.9.6",
-
"prosemirror-view": "^1.14.0"
}
}
diff --git a/src/public-api.ts b/src/public-api.ts
index 3f7b6e74..3103cc11 100644
--- a/src/public-api.ts
+++ b/src/public-api.ts
@@ -4,4 +4,8 @@
export * from './lib/ngx-editor.component';
export * from './lib/ngx-editor.module';
+
export { default as schema } from './lib/schema';
+export * from './lib/prosemirror/plugins';
+export * from './lib/prosemirror/commands';
+export * from './lib/prosemirror/helpers';
diff --git a/wiki/content/configuartion.md b/wiki/content/configuartion.md
index 06da46f5..adaa23c4 100644
--- a/wiki/content/configuartion.md
+++ b/wiki/content/configuartion.md
@@ -4,33 +4,28 @@ The Configuration can be provided using `config` property
## Usage
-```html
-
-
-```
-
-### Default Configuration
-
-The config property is a JSON object. Each array is a group which is seperated by sperator.
-
-```jsonc
-{
- "toolbar": [
- ["bold", "italic", "code"], // inline icons
- ["ordered_list", "bullet_list"],
- [{ "heading": ["h1", "h2", "h3", "h4", "h5", "h6"] }] // dropdown
- ]
-}
-```
-
-Configuration Type definition
-
```ts
-interface Config {
- toolbar: boolean | null | string[][];
-}
+import { menu, placeholder } from "ngx-editor";
+
+NgxEditorModule.forRoot({
+ plugins: [
+ menu({
+ // default options (Optional)
+ toolbar: [
+ ["bold", "italic", "code"], // inline icons
+ ["ordered_list", "bullet_list"],
+ [{ heading: ["h1", "h2", "h3", "h4", "h5", "h6"] }], // dropdown
+ ],
+ labels: {
+ bold: "Bold",
+ italics: "Italics",
+ code: "Code",
+ ordered_list: "Ordered List",
+ bullet_list: "Bullet List",
+ heading: "Heading",
+ },
+ }),
+ placholder("Type something here..."),
+ ],
+});
```
diff --git a/wiki/content/examples.md b/wiki/content/examples.md
new file mode 100644
index 00000000..e9de56cc
--- /dev/null
+++ b/wiki/content/examples.md
@@ -0,0 +1,72 @@
+# Examples
+
+### Implement undo/redo history
+
+Reference
+
+- https://prosemirror.net/docs/ref/#history
+- https://prosemirror.net/docs/ref/#keymap
+
+```ts
+import { undo, redo, history } from "prosemirror-history";
+import { keymap } from "prosemirror-keymap";
+
+NgxEditorModule.forRoot({
+ plugins: [
+ history(), // enable history support
+ keymap({
+ // configure shortcuts
+ "Mod-z": undo,
+ "Shift-Mod-z": redo,
+ }),
+ ],
+});
+```
+
+### Configure shortcts to work with list items
+
+Reference
+
+- https://prosemirror.net/docs/ref/#keymap
+- https://prosemirror.net/docs/ref/#schema-list
+
+```ts
+import { schema } from "ngx-editor";
+import { splitListItem, liftListItem, sinkListItem } from "prosemirror-schema-list";
+import { keymap } from "prosemirror-keymap";
+
+NgxEditorModule.forRoot({
+ plugins: [
+ keymap({
+ Enter: splitListItem(schema.nodes.list_item),
+ "Mod-[": liftListItem(schema.nodes.list_item),
+ "Mod-]": sinkListItem(schema.nodes.list_item),
+ Tab: sinkListItem(schema.nodes.list_item),
+ }),
+ ],
+});
+```
+
+### Extras
+
+Reference
+
+- https://prosemirror.net/docs/ref/#commands
+- https://prosemirror.net/docs/ref/#keymap
+
+```ts
+import { schema } from "ngx-editor";
+import { keymap } from "prosemirror-keymap";
+import { toggleMark, baseKeymap } from "prosemirror-commands";
+
+NgxEditorModule.forRoot({
+ plugins: [
+ keymap({
+ "Mod-b": toggleMark(schema.marks.strong), // toggle strong
+ "Mod-i": toggleMark(schema.marks.em), // toggle italics
+ "Mod-`": toggleMark(schema.marks.code), // toggle code
+ }),
+ keymap(baseKeymap),
+ ],
+});
+```
diff --git a/wiki/content/shortcuts.md b/wiki/content/shortcuts.md
deleted file mode 100644
index c00c410e..00000000
--- a/wiki/content/shortcuts.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# Shortcuts
-
-- **Mod+b** - Toggle Strong
-- **Mod+i** - Toggle Emphasis
-- **Mod+`** - Toggle Code
-- **Mod+Z** - Undo
-- **Shift-Mod-z or Mod-y** - Redo
-- **Mod-[** - Lift the list item around the selection up into a wrapping list
-- **Mod-] or Tab** - Sink the list item around the selection down into an inner list
-
-
-Note: **Mod-** is a shorthand for **Cmd-** on Mac and **Ctrl-** on other platforms.
diff --git a/wiki/summary.json b/wiki/summary.json
index 129a1bfb..c2a7d4e0 100644
--- a/wiki/summary.json
+++ b/wiki/summary.json
@@ -8,7 +8,7 @@
"file": "content/ng-model.md"
},
{
- "title": "Shortcuts",
- "file": "content/shortcuts.md"
+ "title": "Examples",
+ "file": "content/examples.md"
}
]