You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

121 lines
3.3 KiB

/* eslint-disable no-cond-assign */
/* eslint-disable no-plusplus */
import { undoItem, redoItem, icons, MenuItem } from 'prosemirror-menu';
import { toggleMark } from 'prosemirror-commands';
import { wrapInList } from 'prosemirror-schema-list';
import { openPrompt } from './prompt';
import { TextField } from './TextField';
// Helpers to create specific types of items
function cmdItem(cmd, options) {
let passedOptions = {
label: options.title,
run: cmd,
};
Object.keys(options).reduce((acc, optionKey) => {
acc[optionKey] = options[optionKey];
return acc;
}, passedOptions);
if ((!options.enable || options.enable === true) && !options.select)
passedOptions[options.enable ? 'enable' : 'select'] = state => cmd(state);
return new MenuItem(passedOptions);
}
function markActive(state, type) {
let { from, $from, to, empty } = state.selection;
if (empty) return type.isInSet(state.storedMarks || $from.marks());
return state.doc.rangeHasMark(from, to, type);
}
function markItem(markType, options) {
let passedOptions = {
active(state) {
return markActive(state, markType);
},
enable: true,
};
Object.keys(options).reduce((acc, optionKey) => {
acc[optionKey] = options[optionKey];
return acc;
}, passedOptions);
return cmdItem(toggleMark(markType), passedOptions);
}
function linkItem(markType) {
return new MenuItem({
title: 'Add or remove link',
icon: icons.link,
active(state) {
return markActive(state, markType);
},
enable(state) {
return !state.selection.empty;
},
run(state, dispatch, view) {
if (markActive(state, markType)) {
toggleMark(markType)(state, dispatch);
return true;
}
openPrompt({
title: 'Create a link',
fields: {
href: new TextField({
label: 'https://example.com',
class: 'small',
required: true,
}),
},
callback(attrs) {
toggleMark(markType, attrs)(view.state, view.dispatch);
view.focus();
},
});
return false;
},
});
}
function wrapListItem(nodeType, options) {
return cmdItem(wrapInList(nodeType, options.attrs), options);
}
export function buildMenuItems(schema) {
let r = {};
let type;
if ((type = schema.marks.strong))
r.toggleStrong = markItem(type, {
title: 'Toggle strong style',
icon: icons.strong,
});
if ((type = schema.marks.em))
r.toggleEm = markItem(type, { title: 'Toggle emphasis', icon: icons.em });
if ((type = schema.marks.code))
r.toggleCode = markItem(type, {
title: 'Toggle code font',
icon: icons.code,
});
if ((type = schema.marks.link)) r.toggleLink = linkItem(type);
if ((type = schema.nodes.bullet_list))
r.wrapBulletList = wrapListItem(type, {
title: 'Wrap in bullet list',
icon: icons.bulletList,
});
if ((type = schema.nodes.ordered_list))
r.wrapOrderedList = wrapListItem(type, {
title: 'Wrap in ordered list',
icon: icons.orderedList,
});
let cut = arr => arr.filter(x => x);
r.inlineMenu = [
cut([r.toggleStrong, r.toggleEm, r.toggleCode, r.toggleLink]),
];
r.blockMenu = [cut([r.wrapBulletList, r.wrapOrderedList])];
r.fullMenu = r.inlineMenu.concat([[undoItem, redoItem]], r.blockMenu);
return r;
}