UNPKG

jodit

Version:

Jodit is awesome and usefully wysiwyg editor with filebrowser

300 lines (268 loc) 8.1 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 { convertMediaURLToVideoEmbed, isURL, val } from '../modules/helpers/'; import { Select } from '../modules/Selection'; import { IJodit, markerInfo } from '../types'; import { IControlType } from '../types/toolbar'; /** * @property {object} link `{@link link|link}` plugin's options * @property {boolean} link.followOnDblClick=true Follow lnk address after dblclick * @property {boolean} link.processVideoLink=true Replace inserted youtube/vimeo link toWYSIWYG `iframe` * @property {boolean} link.processPastedLink=true Wrap inserted link in &lt;a href="link">link&lt;/a> * @property {boolean} link.openLinkDialogAfterPost=true Open Link dialog after post * @property {boolean} link.removeLinkAfterFormat=true When the button is pressed toWYSIWYG clean format, * if it was done on the link is removed like command `unlink` */ declare module '../Config' { interface Config { link: { followOnDblClick: boolean; processVideoLink: boolean; processPastedLink: boolean; openLinkDialogAfterPost: boolean; removeLinkAfterFormat: boolean; noFollowCheckbox: boolean; openInNewTabCheckbox: boolean; }; } } Config.prototype.link = { followOnDblClick: true, processVideoLink: true, processPastedLink: true, openLinkDialogAfterPost: true, removeLinkAfterFormat: true, noFollowCheckbox: true, openInNewTabCheckbox: true }; Config.prototype.controls.unlink = { exec: (editor: IJodit, current: Node) => { const anchor: HTMLAnchorElement | false = Dom.closest( current, 'A', editor.editor ) as HTMLAnchorElement; if (anchor) { Dom.unwrap(anchor); } editor.events.fire('hidePopup'); } } as IControlType; Config.prototype.controls.link = { isActive: (editor: IJodit): boolean => { const current: Node | false = editor.selection.current(); return current && Dom.closest(current, 'a', editor.editor) !== false; }, popup: ( editor: IJodit, current: HTMLElement | false, self: IControlType, close: () => void ) => { const sel = editor.selection.sel, form: HTMLFormElement = editor.create.fromHTML( '<form class="jodit_form">' + '<input required type="text" name="url" placeholder="http://" type="text"/>' + '<input name="text" placeholder="' + editor.i18n('Text') + '" type="text"/>' + (editor.options.link.openInNewTabCheckbox ? '<label>' + '<input name="target" type="checkbox"/> ' + editor.i18n('Open in new tab') + '</label>' : '') + (editor.options.link.noFollowCheckbox ? '<label>' + '<input name="nofollow" type="checkbox"/> ' + editor.i18n('No follow') + '</label>' : '') + '<div style="text-align: right">' + '<button class="jodit_unlink_button" type="button">' + editor.i18n('Unlink') + '</button> &nbsp;&nbsp;' + '<button class="jodit_link_insert_button" type="submit"></button>' + '</div>' + '<form/>' ) as HTMLFormElement; if (current && Dom.closest(current, 'A', editor.editor)) { current = Dom.closest(current, 'A', editor.editor) as HTMLElement; } else { current = false; } const lnk: HTMLAnchorElement | null = form.querySelector( '.jodit_link_insert_button' ), unlink: HTMLButtonElement | null = form.querySelector( '.jodit_unlink_button' ); if (current) { val(form, 'input[name=url]', current.getAttribute('href') || ''); val(form, 'input[name=text]', current.innerText); if (editor.options.link.openInNewTabCheckbox) { (form.querySelector( 'input[name=target]' ) as HTMLInputElement).checked = current.getAttribute('target') === '_blank'; } if (editor.options.link.noFollowCheckbox) { (form.querySelector( 'input[name=nofollow]' ) as HTMLInputElement).checked = current.getAttribute('rel') === 'nofollow'; } if (lnk) { lnk.innerHTML = editor.i18n('Update'); } } else { if (unlink) { unlink.style.display = 'none'; } val(form, 'input[name=text]', sel ? sel.toString() : ''); if (lnk) { lnk.innerHTML = editor.i18n('Insert'); } } const selInfo: markerInfo[] = editor.selection.save(); if (unlink) { unlink.addEventListener('mousedown', (e: MouseEvent) => { if (current) { Dom.unwrap(current); } editor.selection.restore(selInfo); close(); e.preventDefault(); }); } form.addEventListener('submit', (event: Event) => { event.preventDefault(); editor.selection.restore(selInfo); const a: HTMLAnchorElement = (current as HTMLAnchorElement) || editor.editorDocument.createElement('a'); if (!val(form, 'input[name=url]')) { (form.querySelector( 'input[name=url]' ) as HTMLInputElement).focus(); (form.querySelector( 'input[name=url]' ) as HTMLInputElement).classList.add('jodit_error'); return false; } a.setAttribute('href', val(form, 'input[name=url]')); a.innerText = val(form, 'input[name=text]'); if (editor.options.link.openInNewTabCheckbox) { if ( (form.querySelector( 'input[name=target]' ) as HTMLInputElement).checked ) { a.setAttribute('target', '_blank'); } else { a.removeAttribute('target'); } } if (editor.options.link.noFollowCheckbox) { if ( (form.querySelector( 'input[name=nofollow]' ) as HTMLInputElement).checked ) { a.setAttribute('rel', 'nofollow'); } else { a.removeAttribute('rel'); } } if (!current) { editor.selection.insertNode(a); } close(); return false; }); return form; }, tags: ['a'], tooltip: 'Insert link' } as IControlType; /** * Process link. Insert, dbclick or remove format * * @module plugins/link */ export function link(jodit: IJodit) { if (jodit.options.link.followOnDblClick) { jodit.events.on('afterInit', () => { jodit.events.on( jodit.editor, 'dblclick', function(this: HTMLAnchorElement, e: MouseEvent) { const href: string | null = this.getAttribute('href'); if (href) { location.href = href; e.preventDefault(); } }, 'a' ); }); } if (jodit.options.link.processPastedLink) { jodit.events.on( 'processPaste', (event: ClipboardEvent, html: string): HTMLAnchorElement | void => { if (isURL(html)) { const embed: string = convertMediaURLToVideoEmbed(html); if (embed !== html) { return jodit.create.inside.fromHTML( embed ) as HTMLAnchorElement; } const a: HTMLAnchorElement = jodit.create.inside.element( 'a' ); a.setAttribute('href', html); a.innerText = html; return a; } } ); } if (jodit.options.link.removeLinkAfterFormat) { jodit.events.on('afterCommand', (command: string) => { const sel: Select = jodit.selection; let newtag: Node, node: Node | false; if (command === 'removeFormat') { node = sel.current(); if (node && node.nodeName !== 'A') { node = Dom.closest(node, 'A', jodit.editor); } if (node && node.nodeName === 'A') { if ( (node as HTMLElement).innerHTML === (node as HTMLElement).innerText ) { newtag = jodit.editorDocument.createTextNode( (node as HTMLElement).innerHTML ); } else { newtag = jodit.editorDocument.createElement('span'); (newtag as HTMLElement).innerHTML = (node as HTMLElement).innerHTML; } if (node.parentNode) { node.parentNode.replaceChild(newtag, node); jodit.selection.setCursorIn(newtag, true); } } } }); } }