UNPKG

jodit

Version:

Jodit is an awesome and useful wysiwyg editor with filebrowser

370 lines (369 loc) 14.2 kB
/*! * Jodit Editor (https://xdsoft.net/jodit/) * Released under MIT see LICENSE.txt in the project root for license information. * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net */ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import { autobind } from "../../core/decorators/index.js"; import { Dom } from "../../core/dom/index.js"; import { pluginSystem } from "../../core/global.js"; import { attr, call, convertMediaUrlToVideoEmbed, isString, isURL, refs, stripTags } from "../../core/helpers/index.js"; import { Plugin } from "../../core/plugin/index.js"; import "./config.js"; /** * Process link. Insert, dblclick or remove format */ export class link extends Plugin { constructor() { super(...arguments); /** @override */ this.buttons = [ { name: 'link', group: 'insert' } ]; } /** @override */ afterInit(jodit) { if (jodit.o.link.followOnDblClick) { jodit.e.on('dblclick.link', this.__onDblClickOnLink); } jodit.e.on(jodit.editor, 'click.link', this.__onClickReadOnlyLink); if (jodit.o.link.processPastedLink) { jodit.e.on('processPaste.link', this.onProcessPasteLink); } jodit.e.on('generateLinkForm.link', this.__generateForm); jodit.registerCommand('openLinkDialog', { exec: () => { const dialog = jodit.dlg({ resizable: false }); const htmlForm = this.__generateForm(jodit.s.current(), () => { dialog.close(); }); htmlForm.container.classList.add('jodit-dialog_alert'); dialog.setContent(htmlForm); dialog.open(); jodit.async.requestIdleCallback(() => { const { url_input } = refs(htmlForm.container); url_input === null || url_input === void 0 ? void 0 : url_input.focus(); }); }, hotkeys: jodit.o.link.hotkeys }); } __onDblClickOnLink(e) { if (!Dom.isTag(e.target, 'a')) { return; } const href = attr(e.target, 'href'); if (href) { location.href = href; e.preventDefault(); } } onProcessPasteLink(ignore, html) { var _a, _b, _c, _d; const { jodit } = this; if (!isURL(html) || !jodit.o.link.processPastedLink) { return; } jodit.e.stopPropagation('processPaste'); if (jodit.o.link.processVideoLink) { const embed = call((_b = (_a = jodit.o.video) === null || _a === void 0 ? void 0 : _a.parseUrlToVideoEmbed) !== null && _b !== void 0 ? _b : convertMediaUrlToVideoEmbed, html, { width: (_c = jodit.o.video) === null || _c === void 0 ? void 0 : _c.defaultWidth, height: (_d = jodit.o.video) === null || _d === void 0 ? void 0 : _d.defaultHeight }); if (embed !== html) { return jodit.createInside.fromHTML(embed); } } if (jodit.s.isCollapsed()) { const a = jodit.createInside.element('a'); attr(a, 'href', html); a.textContent = html; jodit.e.fire('applyLink', jodit, a, null); return a; } jodit.s.commitStyle({ element: 'a', attributes: { href: html } }); return true; } __generateForm(current, close) { const { jodit } = this; const i18n = jodit.i18n.bind(jodit); const { openInNewTabCheckbox, openInNewTabCheckboxDefaultChecked, noFollowCheckbox, formTemplate, formClassName, modeClassName } = jodit.o.link; const html = formTemplate(jodit); const form = isString(html) ? jodit.c.fromHTML(html, { target_checkbox_box: openInNewTabCheckbox, nofollow_checkbox_box: noFollowCheckbox }) : html; const htmlForm = Dom.isElement(form) ? form : form.container; const elements = refs(htmlForm); const { insert, unlink, content_input_box } = elements; const { target_checkbox, nofollow_checkbox, url_input } = elements; const currentElement = current; const isImageContent = Dom.isImage(currentElement); let { content_input } = elements; const { className_input } = elements, { className_select } = elements; if (!content_input) { content_input = jodit.c.element('input', { type: 'hidden', ref: 'content_input' }); } if (formClassName) { htmlForm.classList.add(formClassName); } if (isImageContent) { Dom.hide(content_input_box); } let link; const getSelectionText = () => link ? link.innerText : stripTags(jodit.s.range.cloneContents(), jodit.ed); if (current && Dom.closest(current, 'a', jodit.editor)) { link = Dom.closest(current, 'a', jodit.editor); } else { link = false; } if (!isImageContent && current) { content_input.value = getSelectionText(); } if (link) { url_input.value = attr(link, 'href') || ''; if (modeClassName) { readClassnames(modeClassName, className_input, link, className_select); } if (openInNewTabCheckbox && target_checkbox) { target_checkbox.checked = attr(link, 'target') === '_blank'; } if (noFollowCheckbox && nofollow_checkbox) { nofollow_checkbox.checked = (attr(link, 'rel') || '') .split(/\s+/) .includes('nofollow'); } insert.textContent = i18n('Update'); } else { Dom.hide(unlink); if (openInNewTabCheckbox && target_checkbox) { target_checkbox.checked = openInNewTabCheckboxDefaultChecked; } } jodit.editor.normalize(); const snapshot = jodit.history.snapshot.make(); if (unlink) { jodit.e.on(unlink, 'click', (e) => { jodit.s.restore(); jodit.history.snapshot.restore(snapshot); if (link) { Dom.unwrap(link); } jodit.synchronizeValues(); close(); e.preventDefault(); }); } const onSubmit = () => { if (!url_input.value.trim().length) { url_input.focus(); url_input.classList.add('jodit_error'); return false; } let links; jodit.s.restore(); jodit.s.removeMarkers(); jodit.editor.normalize(); jodit.history.snapshot.restore(snapshot); const textWasChanged = getSelectionText() !== content_input.value.trim(); const ci = jodit.createInside; if (!link || !Dom.isOrContains(jodit.editor, link)) { if (!jodit.s.isCollapsed()) { const node = jodit.s.current(); if (Dom.isTag(node, 'img')) { links = [Dom.wrap(node, 'a', ci)]; } else { links = jodit.s.wrapInTag('a'); } } else { const a = ci.element('a'); jodit.s.insertNode(a, false, false); links = [a]; } links.forEach(link => jodit.s.select(link)); } else { links = [link]; } links.forEach(a => { attr(a, 'href', url_input.value); writeClasses(modeClassName, className_input, className_select, a); if (!isImageContent) { writeImage(a, content_input, textWasChanged, url_input); } if (openInNewTabCheckbox && target_checkbox) { attr(a, 'target', target_checkbox.checked ? '_blank' : null); } if (noFollowCheckbox && nofollow_checkbox) { const relParts = (attr(a, 'rel') || '') .split(/\s+/) .filter(Boolean); const hasNofollow = relParts.includes('nofollow'); if (nofollow_checkbox.checked && !hasNofollow) { relParts.push('nofollow'); } else if (!nofollow_checkbox.checked && hasNofollow) { relParts.splice(relParts.indexOf('nofollow'), 1); } attr(a, 'rel', relParts.length ? relParts.join(' ') : null); } jodit.e.fire('applyLink', jodit, a, form); }); jodit.synchronizeValues(); close(); return false; }; if (Dom.isElement(form)) { jodit.e.on(form, 'submit', (event) => { event.preventDefault(); event.stopImmediatePropagation(); onSubmit(); return false; }); } else { form.onSubmit(onSubmit); } return form; } /** @override */ beforeDestruct(jodit) { jodit.e .off('generateLinkForm.link', this.__generateForm) .off('dblclick.link', this.__onDblClickOnLink) .off(jodit.editor, 'click.link', this.__onClickReadOnlyLink) .off('processPaste.link', this.onProcessPasteLink); } __onClickReadOnlyLink(e) { const { jodit } = this; if (jodit.o.readonly && jodit.o.link.preventReadOnlyNavigation && Dom.isTag(e.target, 'a')) { e.preventDefault(); } } } __decorate([ autobind ], link.prototype, "__onDblClickOnLink", null); __decorate([ autobind ], link.prototype, "onProcessPasteLink", null); __decorate([ autobind ], link.prototype, "__generateForm", null); __decorate([ autobind ], link.prototype, "__onClickReadOnlyLink", null); pluginSystem.add('link', link); function writeClasses(modeClassName, className_input, className_select, a) { var _a; if (modeClassName && (className_input !== null && className_input !== void 0 ? className_input : className_select)) { if (modeClassName === 'input') { if (className_input.value === '' && a.hasAttribute('class')) { attr(a, 'class', null); } if (className_input.value !== '') { attr(a, 'class', className_input.value); } } else if (modeClassName === 'select') { if (a.hasAttribute('class')) { attr(a, 'class', null); } for (let i = 0; i < className_select.selectedOptions.length; i++) { const className = (_a = className_select.selectedOptions.item(i)) === null || _a === void 0 ? void 0 : _a.value; if (className) { className .split(/\s+/) .filter(cn => cn.trim().length > 0) .forEach(cn => { a.classList.add(cn); }); } } } } } function readClassnames(modeClassName, className_input, link, className_select) { switch (modeClassName) { case 'input': if (className_input) { className_input.value = attr(link, 'class') || ''; } break; case 'select': if (className_select) { for (let i = 0; i < className_select.selectedOptions.length; i++) { const option = className_select.options.item(i); if (option) { option.selected = false; } } const classNames = attr(link, 'class') || ''; classNames .split(/\s+/) .filter(cn => cn.trim().length > 0) .forEach(className => { if (className) { for (let i = 0; i < className_select.options.length; i++) { const option = className_select.options.item(i); if ((option === null || option === void 0 ? void 0 : option.value) && option.value .split(/\s+/) .map(cn => cn.trim()) .includes(className)) { option.selected = true; } } } }); } break; } } function writeImage(a, content_input, textWasChanged, url_input) { let newContent = a.textContent; if (content_input.value.trim().length) { if (textWasChanged) { newContent = content_input.value; } } else { newContent = url_input.value; } const content = a.textContent; if (newContent !== content) { a.textContent = newContent; } }