import {
BOLD_ICON,
CODE_ICON,
COLOR_ICON,
FILE_ICON,
FONT_SIZE_ICON,
FULLSCREEN_CONTRACT_ICON,
FULLSCREEN_EXPAND_ICON,
H1_ICON,
H2_ICON,
IMAGE_ICON,
ITALIC_ICON,
LINK_ICON,
LIST_CHECK_ICON,
LIST_ORDERED_ICON,
LIST_UNORDERED_ICON,
REDO_ICON,
STRIKE_ICON,
TABLE_ICON,
UNDERLINE_ICON,
UNDO_ICON,
} from './icons-config';
export interface IToolbarItemConfig {
id: string;
name?: string;
exitName?: string;
type?: 'button' | 'dropDown';
icon?: string;
exitIcon?: string;
template?: any;
component?: any;
shortKey?: string;
shortKeyWithCode?: string;
params?: { [key: string]: any };
handler?(editor?: any, params?: any): void;
}
class ToolBarHandler {
static undo = (editor: any): void => {
editor.undo();
};
static redo = (editor: any): void => {
editor.redo();
};
static bold = (editor: any): void => {
const cursor = editor.getCursor();
const selection = editor.getSelection();
editor.replaceSelection('**' + selection + '**');
editor.focus();
if (selection === '') {
editor.setCursor(cursor.line, cursor.ch + 2);
}
};
static italic = (editor: any): void => {
const cursor = editor.getCursor();
const selection = editor.getSelection();
editor.replaceSelection('*' + selection + '*');
editor.focus();
if (selection === '') {
editor.setCursor(cursor.line, cursor.ch + 1);
}
};
static h1 = (editor: any): void => {
const cursor = editor.getCursor();
const selection = editor.getSelection();
editor.focus();
if (cursor.ch !== 0) {
editor.setCursor(cursor.line, 0);
editor.replaceSelection('# ');
} else {
editor.replaceSelection('# ' + selection);
}
};
static h2 = (editor: any): void => {
const cursor = editor.getCursor();
const selection = editor.getSelection();
editor.focus();
if (cursor.ch !== 0) {
editor.setCursor(cursor.line, 0);
editor.replaceSelection('## ');
} else {
editor.replaceSelection('## ' + selection);
}
};
static ul = (editor: any): void => {
const selection = editor.getSelection();
editor.focus();
if (selection === '') {
editor.replaceSelection('- ' + selection);
} else {
const selectionText = selection.split('\n');
for (let i = 0, len = selectionText.length; i < len; i++) {
selectionText[i] = selectionText[i] === '' ? '' : '- ' + selectionText[i];
}
editor.replaceSelection(selectionText.join('\n'));
}
};
static ol = (editor: any): void => {
const selection = editor.getSelection();
editor.focus();
if (selection === '') {
editor.replaceSelection('1. ' + selection);
} else {
const selectionText = selection.split('\n');
for (let i = 0, len = selectionText.length; i < len; i++) {
selectionText[i] = selectionText[i] === '' ? '' : i + 1 + '. ' + selectionText[i];
}
editor.replaceSelection(selectionText.join('\n'));
}
};
static underline = (editor: any): void => {
const cursor = editor.getCursor();
const selection = editor.getSelection();
editor.focus();
editor.replaceSelection('<ins>' + selection + '</ins>');
if (selection === '') {
editor.setCursor(cursor.line, cursor.ch + 5);
}
};
static strike = (editor: any): void => {
const cursor = editor.getCursor();
const selection = editor.getSelection();
editor.replaceSelection('~~' + selection + '~~');
editor.focus();
if (selection === '') {
editor.setCursor(cursor.line, cursor.ch + 2);
}
};
static checkList = (editor: any): void => {
const selection = editor.getSelection();
editor.focus();
if (selection === '') {
editor.replaceSelection('[ ] ' + selection);
} else {
const selectionText = selection.split('\n');
for (let i = 0, len = selectionText.length; i < len; i++) {
selectionText[i] = selectionText[i] === '' ? '' : '[ ] ' + selectionText[i];
}
editor.replaceSelection(selectionText.join('\n'));
}
};
static font = (): void => {};
static link = (editor: any): void => {
const cursor = editor.getCursor();
const selection = editor.getSelection();
editor.focus();
editor.replaceSelection('[' + selection + '](url)');
if (selection === '') {
editor.setCursor(cursor.line, cursor.ch + 1);
}
};
static image = (editor: any, params?: any): void => {
const stopEventPropagation = (e: any): void => {
e.stopPropagation();
};
if (typeof document !== 'undefined' && params.imageUploadToServer) {
let imageUploader = document.getElementById('markdown_image_upload_input');
if (imageUploader) {
imageUploader.removeEventListener('click', stopEventPropagation);
document.body.removeChild(imageUploader);
}
imageUploader = document.createElement('input');
imageUploader.addEventListener('click', stopEventPropagation);
imageUploader.setAttribute('type', 'file');
imageUploader.setAttribute('accept', 'image/bmp,image/gif,image/jpeg,image/jpg,image/png,image/tiff');
imageUploader.id = 'markdown_image_upload_input';
imageUploader.style.display = 'none';
document.body.appendChild(imageUploader);
const callback = ({ name, imgUrl, title }: any) => {
editor.focus();
editor.replaceSelection(``);
};
imageUploader.onchange = (e: any) => {
const file = e.target['files'][0];
params.imageUpload({ file, callback });
};
imageUploader.click();
} else {
const cursor = editor.getCursor();
const selection = editor.getSelection();
editor.focus();
editor.replaceSelection('");
if (selection === '') {
editor.setCursor(cursor.line, cursor.ch + 2);
}
}
};
static file = (editor: any, params?: any): void => {
const stopEventPropagation = (e: any): void => {
e.stopPropagation();
};
let fileUploader = document.getElementById('markdown_file_upload_input');
if (fileUploader) {
fileUploader.removeEventListener('click', stopEventPropagation);
document.body.removeChild(fileUploader);
}
fileUploader = document.createElement('input');
fileUploader.setAttribute('type', 'file');
fileUploader.addEventListener('click', stopEventPropagation);
fileUploader.id = 'markdown_file_upload_input';
fileUploader.style.display = 'none';
document.body.appendChild(fileUploader);
const callback = ({ name, url, title, isImage }: any) => {
let showAsImage = false;
if (isImage !== undefined) {
showAsImage = isImage;
} else if (url) {
const imageFilter = /^(bmp|gif|jpeg|jpg|png|tiff)$/i;
showAsImage = imageFilter.test(url.split('.').pop());
}
editor.focus();
if (showAsImage) {
editor.replaceSelection(``);
} else {
editor.replaceSelection(`[${name}](${url} '${title}')`);
}
};
fileUploader.onchange = (e: any) => {
const file = e.target['files'][0];
params.fileUpload.emit({ file, callback });
};
fileUploader.click();
};
static code = (editor: any): void => {
const cursor = editor.getCursor();
const selection = editor.getSelection();
if (selection.indexOf('\n') === -1) {
editor.replaceSelection('`' + selection + '`');
} else {
editor.replaceSelection('```\n' + selection + '\n```');
}
editor.focus();
if (selection === '') {
editor.setCursor(cursor.line, cursor.ch + 1);
}
};
static table = (editor: any) => {
const table = `\n| | | |\n|--|--|--|\n| | | |`;
editor.replaceSelection(table);
};
static fullscreen = (editor: any) => {
editor.focus();
};
static color = (): void => {};
}
export const GET_CTRL_KEY = () => {
if (typeof window !== 'undefined') {
return navigator?.platform?.indexOf('Mac') !== -1 ? '⌘' : 'Ctrl';
}
}
export const GET_ALT_KEY = () => {
if (typeof window !== 'undefined') {
return navigator?.platform?.indexOf('Mac') !== -1 ? '⌥' : 'Alt';
}
}
export const DEFAULT_TOOLBARS: Record<string, IToolbarItemConfig> = {
undo: {
id: 'undo',
name: 'undo',
type: 'button',
icon: UNDO_ICON,
shortKey: `${GET_CTRL_KEY()}+Z`,
shortKeyWithCode: `${GET_CTRL_KEY()}+90`,
handler: ToolBarHandler.undo,
},
redo: {
id: 'redo',
name: 'redo',
type: 'button',
icon: REDO_ICON,
shortKey: `${GET_CTRL_KEY()}+Y`,
shortKeyWithCode: `${GET_CTRL_KEY()}+89`,
handler: ToolBarHandler.redo,
},
bold: {
id: 'bold',
name: 'bold',
type: 'button',
icon: BOLD_ICON,
shortKey: `${GET_CTRL_KEY()}+B`,
shortKeyWithCode: `${GET_CTRL_KEY()}+66`,
handler: ToolBarHandler.bold,
},
italic: {
id: 'italic',
name: 'italic',
type: 'button',
icon: ITALIC_ICON,
shortKey: `${GET_CTRL_KEY()}+I`,
shortKeyWithCode: `${GET_CTRL_KEY()}+73`,
handler: ToolBarHandler.italic,
},
strike: {
id: 'strike',
name: 'strike',
type: 'button',
icon: STRIKE_ICON,
shortKey: `${GET_CTRL_KEY()}+D`,
shortKeyWithCode: `${GET_CTRL_KEY()}+68`,
handler: ToolBarHandler.strike,
},
h1: {
id: 'h1',
name: 'h1',
type: 'button',
icon: H1_ICON,
shortKey: `${GET_CTRL_KEY()}+1`,
shortKeyWithCode: `${GET_CTRL_KEY()}+49`,
handler: ToolBarHandler.h1,
},
h2: {
id: 'h2',
name: 'h2',
type: 'button',
icon: H2_ICON,
shortKey: `${GET_CTRL_KEY()}+2`,
shortKeyWithCode: `${GET_CTRL_KEY()}+50`,
handler: ToolBarHandler.h2,
},
ul: {
id: 'ul',
name: 'unorderedlist',
type: 'button',
icon: LIST_UNORDERED_ICON,
shortKey: `${GET_CTRL_KEY()}+U`,
shortKeyWithCode: `${GET_CTRL_KEY()}+85`,
handler: ToolBarHandler.ul,
},
ol: {
id: 'ol',
name: 'orderedlist',
type: 'button',
icon: LIST_ORDERED_ICON,
shortKey: `${GET_CTRL_KEY()}+O`,
shortKeyWithCode: `${GET_CTRL_KEY()}+79`,
handler: ToolBarHandler.ol,
},
checklist: {
id: 'checklist',
name: 'checklist',
type: 'button',
icon: LIST_CHECK_ICON,
shortKey: `${GET_CTRL_KEY()}+${GET_ALT_KEY()}+C`,
shortKeyWithCode: `${GET_CTRL_KEY()}+${GET_ALT_KEY()}+67`,
handler: ToolBarHandler.checkList,
},
underline: {
id: 'underline',
name: 'underline',
type: 'button',
icon: UNDERLINE_ICON,
shortKey: `${GET_CTRL_KEY()}+R`,
shortKeyWithCode: `${GET_CTRL_KEY()}+82`,
handler: ToolBarHandler.underline,
},
font: {
id: 'font',
name: 'size',
type: 'dropDown',
icon: FONT_SIZE_ICON,
component: 'FontSize',
handler: ToolBarHandler.font,
},
link: {
id: 'link',
name: 'link',
type: 'button',
icon: LINK_ICON,
shortKey: `${GET_CTRL_KEY()}+L`,
shortKeyWithCode: `${GET_CTRL_KEY()}+76`,
handler: ToolBarHandler.link,
},
image: {
id: 'image',
name: 'image',
type: 'button',
icon: IMAGE_ICON,
shortKey: `${GET_CTRL_KEY()}+G`,
shortKeyWithCode: `${GET_CTRL_KEY()}+71`,
params: { imageUploadToServer: false },
handler: ToolBarHandler.image,
},
file: {
id: 'file',
name: 'file',
type: 'button',
icon: FILE_ICON,
params: {},
shortKey: `${GET_CTRL_KEY()}+F`,
shortKeyWithCode: `${GET_CTRL_KEY()}+70`,
handler: ToolBarHandler.file,
},
code: {
id: 'code',
name: 'code',
type: 'button',
icon: CODE_ICON,
shortKey: `${GET_CTRL_KEY()}+K`,
shortKeyWithCode: `${GET_CTRL_KEY()}+75`,
handler: ToolBarHandler.code,
},
table: {
id: 'table',
name: 'table',
type: 'button',
icon: TABLE_ICON,
shortKey: `${GET_CTRL_KEY()}+${GET_ALT_KEY()}+T`,
shortKeyWithCode: `${GET_CTRL_KEY()}+${GET_ALT_KEY()}+84`,
handler: ToolBarHandler.table,
},
fullscreen: {
id: 'fullscreen',
name: 'fullscreen',
exitName: 'exit-fullscreen',
type: 'button',
icon: FULLSCREEN_EXPAND_ICON,
exitIcon: FULLSCREEN_CONTRACT_ICON,
handler: ToolBarHandler.fullscreen,
},
color: {
id: 'color',
name: 'color&background',
type: 'dropDown',
icon: COLOR_ICON,
component: 'FontColor',
handler: ToolBarHandler.color,
},
};
export const DEFAULT_TOOLBAR_CONFIG = [
['undo', 'redo'],
['h1', 'h2', 'bold', 'italic', 'strike', 'underline', 'color', 'font'],
['ul', 'ol', 'checklist', 'code', 'link', 'image', 'table'],
'fullscreen',
];
export const FONT_COLORS = [
'#000000',
'#e60000',
'#ff9900',
'#ffff00',
'#008a00',
'#0066cc',
'#9933ff',
'#ffffff',
'#facccc',
'#ffebcc',
'#ffffcc',
'#cce8cc',
'#cce0f5',
'#ebd6ff',
'#bbbbbb',
'#f06666',
'#ffc266',
'#ffff66',
'#66b966',
'#66a3e0',
'#c285ff',
'#888888',
'#a10000',
'#b26b00',
'#b2b200',
'#006100',
'#0047b2',
'#6b24b2',
'#444444',
'#5c0000',
'#663d00',
'#666600',
'#003700',
'#002966',
'#3d1466',
];
export const FONT_SIZE_LIST = [12, 14, 16, 18, 20, 24, 36, 48].map((item) => ({ name: item + 'px', value: item }));