UNPKG

jodit

Version:

Jodit is awesome and usefully wysiwyg editor with filebrowser

311 lines (279 loc) 7.35 kB
/*! * Jodit Editor (https://xdsoft.net/jodit/) * Licensed under GNU General Public License version 2 or later or a commercial license or MIT; * For GPL see LICENSE-GPL.txt in the project root for license information. * For MIT see LICENSE-MIT.txt in the project root for license information. * For commercial licenses see https://xdsoft.net/jodit/commercial/ * Copyright (c) 2013-2019 Valeriy Chupurnov. All rights reserved. https://xdsoft.net */ import { Config } from '../Config'; import { Dom } from '../modules/Dom'; import { debounce, setTimeout } from '../modules/helpers/async'; import { offset } from '../modules/helpers/size'; import { ToolbarIcon } from '../modules/toolbar/icon'; import { IBound, IJodit } from '../types'; declare module '../Config' { interface Config { addNewLine: boolean; addNewLineTagsTriggers: string[]; addNewLineOnDBLClick: boolean; } } /** * Create helper * @type {boolean} */ Config.prototype.addNewLine = true; /** * On dbl click on empty space of editor it add new P element * @type {boolean} */ Config.prototype.addNewLineOnDBLClick = true; /** * Whar kind of tags it will be impact * @type {string[]} */ Config.prototype.addNewLineTagsTriggers = [ 'table', 'iframe', 'img', 'hr', 'jodit' ]; /** * Create helper for adding new paragraph(Jodit.defaultOptions.enter tag) before iframe, table or image * * @param {Jodit} editor */ export function addNewLine(editor: IJodit) { if (!editor.options.addNewLine) { return; } const line: HTMLDivElement = editor.create.fromHTML( '<div role="button" tabIndex="-1" title="' + editor.i18n('Break') + '" class="jodit-add-new-line"><span>' + ToolbarIcon.getIcon('enter') + '</span></div>' ) as HTMLDivElement; const delta = 10; const isMatchedTag = new RegExp( '^(' + editor.options.addNewLineTagsTriggers.join('|') + ')$', 'i' ); let timeout: number; let hidden: boolean = false; let preview: boolean = false; let current: HTMLElement | false; let lineInFocus: boolean = false; const show = () => { if (editor.options.readonly || editor.isLocked()) { return; } if (editor.container.classList.contains('jodit_popup_active')) { return; } clearTimeout(timeout); line.classList.toggle('jodit-add-new-line_after', !preview); line.style.display = 'block'; line.style.width = editor.editor.clientWidth + 'px'; hidden = false; }; const hideForce = () => { clearTimeout(timeout); lineInFocus = false; line.style.display = 'none'; hidden = true; }; const canGetFocus = (elm: Node | null): boolean => { return ( elm !== null && Dom.isBlock(elm, editor.editorWindow) && !/^(img|table|iframe|hr)$/i.test(elm.nodeName) ); }; const hide = () => { if (hidden || lineInFocus) { return; } clearTimeout(timeout); timeout = setTimeout(hideForce, 500); }; editor.events .on('beforeDestruct', () => { Dom.safeRemove(line); }) .on('afterInit', () => { editor.container.appendChild(line); editor.events .on(line, 'mousemove', (e: MouseEvent) => { e.stopPropagation(); }) .on(line, 'mousedown touchstart', (e: MouseEvent) => { const p: HTMLElement = editor.editorDocument.createElement( editor.options.enter ); if (preview && current && current.parentNode) { current.parentNode.insertBefore(p, current); } else { editor.editor.appendChild(p); } editor.selection.setCursorIn(p); editor.events.fire('synchro'); hideForce(); e.preventDefault(); }); }) .on('afterInit', () => { editor.events .on(editor.editor, 'scroll', () => { hideForce(); }) .on(editor.container, 'mouseleave', hide) .on(line, 'mouseenter', () => { clearTimeout(timeout); lineInFocus = true; }) .on(line, 'mouseleave', () => { lineInFocus = false; }) .on(editor.editor, 'dblclick', (e: MouseEvent) => { if ( !editor.options.readonly && editor.options.addNewLineOnDBLClick && e.target === editor.editor && editor.selection.isCollapsed() ) { const editorBound: IBound = offset( editor.editor, editor, editor.editorDocument ); const top: number = e.pageY - editor.editorWindow.pageYOffset; const p: HTMLElement = editor.editorDocument.createElement( editor.options.enter ); if ( Math.abs(top - editorBound.top) < Math.abs( top - (editorBound.height + editorBound.top) ) && editor.editor.firstChild ) { editor.editor.insertBefore( p, editor.editor.firstChild ); } else { editor.editor.appendChild(p); } editor.selection.setCursorIn(p); editor.setEditorValue(); hideForce(); e.preventDefault(); } }) .on( editor.editor, 'mousemove', debounce((e: MouseEvent) => { let currentElement: HTMLElement = editor.editorDocument.elementFromPoint( e.pageX - editor.editorWindow.pageXOffset, e.pageY - editor.editorWindow.pageYOffset ) as HTMLElement; if ( currentElement && Dom.isOrContains(line, currentElement) ) { return; } if ( !currentElement || !Dom.isOrContains(editor.editor, currentElement) ) { return; } if ( !currentElement || !currentElement.nodeName.match(isMatchedTag) || !Dom.isOrContains(editor.editor, currentElement) ) { currentElement = Dom.closest( currentElement, isMatchedTag, editor.editor ) as HTMLElement; if (!currentElement) { hide(); return; } } if (isMatchedTag.test(currentElement.nodeName)) { const parentBox: Node | false = Dom.up( currentElement, node => Dom.isBlock(node, editor.editorWindow), editor.editor ); if (parentBox && parentBox !== editor.editor) { currentElement = parentBox as HTMLElement; } } const editorBound: IBound = offset( editor.editor, editor, editor.editorDocument ); const position: IBound = offset( currentElement as HTMLElement, editor, editor.editorDocument ); let top: false | number = false; if (Math.abs(e.pageY - position.top) < delta) { top = position.top; if (top - editorBound.top >= 20) { top -= 15; } preview = true; } if ( Math.abs( e.pageY - (position.top + position.height) ) < delta ) { top = position.top + position.height; if ( editorBound.top + editorBound.height - top >= 25 ) { top += 15; } preview = false; } if ( top !== false && ((preview && !Dom.prev( currentElement, canGetFocus, editor.editor )) || (!preview && !Dom.next( currentElement, canGetFocus, editor.editor ))) ) { line.style.top = top + 'px'; current = currentElement; show(); } else { current = false; hide(); } }, editor.defaultTimeout) ); }); }