UNPKG

primeng

Version:

PrimeNG is a premium UI library for Angular featuring a rich set of 90+ components, a theme designer, various theme alternatives such as Material, Bootstrap, Tailwind, premium templates and professional support. In addition, it integrates with PrimeBlock,

497 lines (492 loc) 25.9 kB
export * from 'primeng/types/editor'; import { isPlatformServer, NgTemplateOutlet } from '@angular/common'; import * as i0 from '@angular/core'; import { Injectable, InjectionToken, forwardRef, inject, input, output, contentChild, computed, effect, afterNextRender, ViewEncapsulation, ChangeDetectionStrategy, Component, NgModule } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { findSingle } from '@primeuix/utils'; import { Header, SharedModule } from 'primeng/api'; import { PARENT_INSTANCE } from 'primeng/basecomponent'; import { BaseEditableHolder } from 'primeng/baseeditableholder'; import * as i1 from 'primeng/bind'; import { Bind, BindModule } from 'primeng/bind'; import { style } from '@primeuix/styles/editor'; import { BaseStyle } from 'primeng/base'; const classes = { root: ({ instance }) => [ 'p-editor', { 'p-invalid': instance.invalid() } ], toolbar: 'p-editor-toolbar', content: 'p-editor-content' }; class EditorStyle extends BaseStyle { name = 'editor'; style = style; classes = classes; static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: EditorStyle, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: EditorStyle }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: EditorStyle, decorators: [{ type: Injectable }] }); /** * * Editor groups a collection of contents in tabs. * * [Live Demo](https://www.primeng.org/editor/) * * @module editorstyle * */ var EditorClasses; (function (EditorClasses) { /** * Class name of the root element */ EditorClasses["root"] = "p-editor"; /** * Class name of the toolbar element */ EditorClasses["toolbar"] = "p-editor-toolbar"; /** * Class name of the content element */ EditorClasses["content"] = "p-editor-content"; })(EditorClasses || (EditorClasses = {})); const EDITOR_INSTANCE = new InjectionToken('EDITOR_INSTANCE'); const EDITOR_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Editor), multi: true }; /** * Editor groups a collection of contents in tabs. * @group Components * @deprecated Editor will be removed in a future release in favor of PrimeUI PRO Editor. */ class Editor extends BaseEditableHolder { componentName = 'Editor'; $pcEditor = inject(EDITOR_INSTANCE, { optional: true, skipSelf: true }) ?? undefined; bindDirectiveInstance = inject(Bind, { self: true }); onAfterViewChecked() { this.bindDirectiveInstance.setAttrs(this.ptms(['host', 'root'])); } /** * Inline style of the container. * @group Props */ style = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "style" }] : /* istanbul ignore next */ [])); /** * Placeholder text to show when editor is empty. * @group Props */ placeholder = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "placeholder" }] : /* istanbul ignore next */ [])); /** * Whitelist of formats to display, see [here](https://quilljs.com/docs/formats/) for available options. * @group Props */ formats = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "formats" }] : /* istanbul ignore next */ [])); /** * Modules configuration of Editor, see [here](https://quilljs.com/docs/modules/) for available options. * @group Props */ modules = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "modules" }] : /* istanbul ignore next */ [])); /** * DOM Element or a CSS selector for a DOM Element, within which the editor's p elements (i.e. tooltips, etc.) should be confined. Currently, it only considers left and right boundaries. * @group Props */ bounds = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "bounds" }] : /* istanbul ignore next */ [])); /** * DOM Element or a CSS selector for a DOM Element, specifying which container has the scrollbars (i.e. overflow-y: auto), if is has been changed from the default ql-editor with custom CSS. Necessary to fix scroll jumping bugs when Quill is set to auto grow its height, and another ancestor container is responsible from the scrolling.. * @group Props */ scrollingContainer = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "scrollingContainer" }] : /* istanbul ignore next */ [])); /** * Shortcut for debug. Note debug is a static method and will affect other instances of Quill editors on the page. Only warning and error messages are enabled by default. * @group Props */ debug = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "debug" }] : /* istanbul ignore next */ [])); /** * Whether to instantiate the editor to read-only mode. * @group Props */ readonly = input(false, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ [])); /** * Callback to invoke when the quill modules are loaded. * @param {EditorInitEvent} event - custom event. * @group Emits */ onEditorInit = output({ alias: 'onInit' }); /** * Callback to invoke when text of editor changes. * @param {EditorTextChangeEvent} event - custom event. * @group Emits */ onTextChange = output(); /** * Callback to invoke when selection of the text changes. * @param {EditorSelectionChangeEvent} event - custom event. * @group Emits */ onSelectionChange = output(); /** * Callback to invoke when editor content changes (combines both text and selection changes). * @param {EditorChangeEvent} event - custom event. * @group Emits */ onEditorChange = output(); /** * Callback to invoke when editor receives focus. * @param {EditorFocusEvent} event - custom event. * @group Emits */ onFocus = output(); /** * Callback to invoke when editor loses focus. * @param {EditorBlurEvent} event - custom event. * @group Emits */ onBlur = output(); toolbar = contentChild(Header, { ...(ngDevMode ? { debugName: "toolbar" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom item template. * @group Templates */ headerTemplate = contentChild('header', { ...(ngDevMode ? { debugName: "headerTemplate" } : /* istanbul ignore next */ {}), descendants: false }); $hasCustomToolbar = computed(() => !!this.toolbar() || !!this.headerTemplate(), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$hasCustomToolbar" }] : /* istanbul ignore next */ [])); value; delayedCommand = null; quill; dynamicQuill; _destroyed = false; get isAttachedQuillEditorToDOM() { return this.quillElements?.editorElement?.isConnected; } quillElements; focusListener = null; blurListener = null; _componentStyle = inject(EditorStyle); constructor() { super(); effect(() => { const isReadonly = this.readonly(); if (this.quill) { if (isReadonly) this.quill.disable(); else this.quill.enable(); } }); /** * Read or write the DOM once, when initializing non-Angular (Quill) library. */ afterNextRender(() => { this.initQuillElements(); this.initQuillEditor(); }); } /** * @override * * @see {@link BaseEditableHolder.writeControlValue} * Writes the value to the control. */ writeControlValue(value) { if (this.quill && this.value === value) { return; } this.value = value; if (this.quill) { if (value) { const command = () => { this.quill.setContents(this.quill.clipboard.convert(this.dynamicQuill.version.startsWith('2') ? { html: this.value } : this.value)); }; if (this.isAttachedQuillEditorToDOM) { command(); } else { this.delayedCommand = command; } } else { const command = () => { this.quill.setText(''); }; if (this.isAttachedQuillEditorToDOM) { command(); } else { this.delayedCommand = command; } } } } getQuill() { return this.quill; } initQuillEditor() { if (isPlatformServer(this.platformId)) { return; } /** * Importing Quill at top level, throws `document is undefined` error during when * building for SSR, so this dynamically loads quill when it's in browser module. */ if (!this.dynamicQuill) { import('quill') .then((quillModule) => { this.dynamicQuill = quillModule.default; this.createQuillEditor(); }) .catch((e) => console.error(e.message)); } else { this.createQuillEditor(); } } createQuillEditor() { // The Quill module is imported asynchronously; if the component was destroyed before the // import resolved, bail so we don't build Quill and emit (onEditorInit etc.) after destroy. if (this._destroyed) return; this.initQuillElements(); const { toolbarElement, editorElement } = this.quillElements; let defaultModule = { toolbar: toolbarElement }; let modules = this.modules() ? { ...defaultModule, ...this.modules() } : defaultModule; this.quill = new this.dynamicQuill(editorElement, { modules: modules, placeholder: this.placeholder(), readOnly: this.readonly(), theme: 'snow', formats: this.formats(), bounds: this.bounds(), debug: this.debug(), scrollingContainer: this.scrollingContainer() }); const isQuill2 = this.dynamicQuill.version.startsWith('2'); if (this.value) { this.quill.setContents(this.quill.clipboard.convert(isQuill2 ? { html: this.value } : this.value)); } this.quill.on('text-change', (delta, oldContents, source) => { if (this._destroyed) return; if (source === 'user') { let html = isQuill2 ? this.quill.getSemanticHTML() : findSingle(editorElement, '.ql-editor')?.innerHTML; let text = this.quill.getText().trim(); if (html === '<p><br></p>') { html = null; } this.onTextChange.emit({ htmlValue: html, textValue: text, delta: delta, source: source }); this.value = html; this.onModelChange(html); this.onModelTouched(); } }); this.quill.on('selection-change', (range, oldRange, source) => { if (this._destroyed) return; this.onSelectionChange.emit({ range: range, oldRange: oldRange, source: source }); }); this.quill.on('editor-change', (eventName, ...args) => { if (this._destroyed) return; this.onEditorChange.emit({ eventName: eventName, args: args }); }); const editorEl = this.quill.root; this.focusListener = () => { this.onFocus.emit({ source: 'user' }); }; this.blurListener = () => { this.onBlur.emit({ source: 'user' }); }; editorEl.addEventListener('focus', this.focusListener); editorEl.addEventListener('blur', this.blurListener); this.onEditorInit.emit({ editor: this.quill }); } onDestroy() { this._destroyed = true; if (this.quill && this.quill.root) { const editorEl = this.quill.root; if (this.focusListener) { editorEl.removeEventListener('focus', this.focusListener); this.focusListener = null; } if (this.blurListener) { editorEl.removeEventListener('blur', this.blurListener); this.blurListener = null; } } } initQuillElements() { if (!this.quillElements) { this.quillElements = { editorElement: findSingle(this.el.nativeElement, 'div[data-pc-section="content"]'), toolbarElement: findSingle(this.el.nativeElement, 'div[data-pc-section="toolbar"]') }; } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: Editor, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: Editor, isStandalone: true, selector: "p-editor", inputs: { style: { classPropertyName: "style", publicName: "style", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, formats: { classPropertyName: "formats", publicName: "formats", isSignal: true, isRequired: false, transformFunction: null }, modules: { classPropertyName: "modules", publicName: "modules", isSignal: true, isRequired: false, transformFunction: null }, bounds: { classPropertyName: "bounds", publicName: "bounds", isSignal: true, isRequired: false, transformFunction: null }, scrollingContainer: { classPropertyName: "scrollingContainer", publicName: "scrollingContainer", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onEditorInit: "onInit", onTextChange: "onTextChange", onSelectionChange: "onSelectionChange", onEditorChange: "onEditorChange", onFocus: "onFocus", onBlur: "onBlur" }, host: { properties: { "class": "cn(cx('root'))" } }, providers: [EDITOR_VALUE_ACCESSOR, EditorStyle, { provide: EDITOR_INSTANCE, useExisting: Editor }, { provide: PARENT_INSTANCE, useExisting: Editor }], queries: [{ propertyName: "toolbar", first: true, predicate: Header, isSignal: true }, { propertyName: "headerTemplate", first: true, predicate: ["header"], isSignal: true }], usesInheritance: true, hostDirectives: [{ directive: i1.Bind }], ngImport: i0, template: ` @if ($hasCustomToolbar()) { <div [class]="cx('toolbar')" [pBind]="ptm('toolbar')"> <ng-content select="p-header" /> <ng-container *ngTemplateOutlet="headerTemplate()"></ng-container> </div> } @else { <div [class]="cx('toolbar')" [pBind]="ptm('toolbar')"> <span class="ql-formats" [pBind]="ptm('formats')"> <select class="ql-header" [pBind]="ptm('header')"> <option value="1" [pBind]="ptm('option')">Heading</option> <option value="2" [pBind]="ptm('option')">Subheading</option> <option selected [pBind]="ptm('option')">Normal</option> </select> <select class="ql-font" [pBind]="ptm('select')"> <option selected [pBind]="ptm('option')">Sans Serif</option> <option value="serif" [pBind]="ptm('option')">Serif</option> <option value="monospace" [pBind]="ptm('option')">Monospace</option> </select> </span> <span class="ql-formats" [pBind]="ptm('formats')"> <button class="ql-bold" aria-label="Bold" type="button" [pBind]="ptm('bold')"></button> <button class="ql-italic" aria-label="Italic" type="button" [pBind]="ptm('italic')"></button> <button class="ql-underline" aria-label="Underline" type="button" [pBind]="ptm('underline')"></button> </span> <span class="ql-formats" [pBind]="ptm('formats')"> <select class="ql-color" [pBind]="ptm('color')"></select> <select class="ql-background" [pBind]="ptm('background')"></select> </span> <span class="ql-formats" [pBind]="ptm('formats')"> <button class="ql-list" value="ordered" aria-label="Ordered List" type="button" [pBind]="ptm('list')"></button> <button class="ql-list" value="bullet" aria-label="Unordered List" type="button" [pBind]="ptm('list')"></button> <select class="ql-align" [pBind]="ptm('select')"> <option selected [pBind]="ptm('option')"></option> <option value="center" [pBind]="ptm('option')">center</option> <option value="right" [pBind]="ptm('option')">right</option> <option value="justify" [pBind]="ptm('option')">justify</option> </select> </span> <span class="ql-formats" [pBind]="ptm('formats')"> <button class="ql-link" aria-label="Insert Link" type="button" [pBind]="ptm('link')"></button> <button class="ql-image" aria-label="Insert Image" type="button" [pBind]="ptm('image')"></button> <button class="ql-code-block" aria-label="Insert Code Block" type="button" [pBind]="ptm('codeBlock')"></button> </span> <span class="ql-formats" [pBind]="ptm('formats')"> <button class="ql-clean" aria-label="Remove Styles" type="button" [pBind]="ptm('clean')"></button> </span> </div> } <div [class]="cx('content')" [style]="style()" [pBind]="ptm('content')"></div> `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: SharedModule }, { kind: "ngmodule", type: BindModule }, { kind: "directive", type: i1.Bind, selector: "[pBind]", inputs: ["pBind"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: Editor, decorators: [{ type: Component, args: [{ selector: 'p-editor', standalone: true, imports: [NgTemplateOutlet, SharedModule, BindModule], template: ` @if ($hasCustomToolbar()) { <div [class]="cx('toolbar')" [pBind]="ptm('toolbar')"> <ng-content select="p-header" /> <ng-container *ngTemplateOutlet="headerTemplate()"></ng-container> </div> } @else { <div [class]="cx('toolbar')" [pBind]="ptm('toolbar')"> <span class="ql-formats" [pBind]="ptm('formats')"> <select class="ql-header" [pBind]="ptm('header')"> <option value="1" [pBind]="ptm('option')">Heading</option> <option value="2" [pBind]="ptm('option')">Subheading</option> <option selected [pBind]="ptm('option')">Normal</option> </select> <select class="ql-font" [pBind]="ptm('select')"> <option selected [pBind]="ptm('option')">Sans Serif</option> <option value="serif" [pBind]="ptm('option')">Serif</option> <option value="monospace" [pBind]="ptm('option')">Monospace</option> </select> </span> <span class="ql-formats" [pBind]="ptm('formats')"> <button class="ql-bold" aria-label="Bold" type="button" [pBind]="ptm('bold')"></button> <button class="ql-italic" aria-label="Italic" type="button" [pBind]="ptm('italic')"></button> <button class="ql-underline" aria-label="Underline" type="button" [pBind]="ptm('underline')"></button> </span> <span class="ql-formats" [pBind]="ptm('formats')"> <select class="ql-color" [pBind]="ptm('color')"></select> <select class="ql-background" [pBind]="ptm('background')"></select> </span> <span class="ql-formats" [pBind]="ptm('formats')"> <button class="ql-list" value="ordered" aria-label="Ordered List" type="button" [pBind]="ptm('list')"></button> <button class="ql-list" value="bullet" aria-label="Unordered List" type="button" [pBind]="ptm('list')"></button> <select class="ql-align" [pBind]="ptm('select')"> <option selected [pBind]="ptm('option')"></option> <option value="center" [pBind]="ptm('option')">center</option> <option value="right" [pBind]="ptm('option')">right</option> <option value="justify" [pBind]="ptm('option')">justify</option> </select> </span> <span class="ql-formats" [pBind]="ptm('formats')"> <button class="ql-link" aria-label="Insert Link" type="button" [pBind]="ptm('link')"></button> <button class="ql-image" aria-label="Insert Image" type="button" [pBind]="ptm('image')"></button> <button class="ql-code-block" aria-label="Insert Code Block" type="button" [pBind]="ptm('codeBlock')"></button> </span> <span class="ql-formats" [pBind]="ptm('formats')"> <button class="ql-clean" aria-label="Remove Styles" type="button" [pBind]="ptm('clean')"></button> </span> </div> } <div [class]="cx('content')" [style]="style()" [pBind]="ptm('content')"></div> `, providers: [EDITOR_VALUE_ACCESSOR, EditorStyle, { provide: EDITOR_INSTANCE, useExisting: Editor }, { provide: PARENT_INSTANCE, useExisting: Editor }], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { '[class]': "cn(cx('root'))" }, hostDirectives: [Bind] }] }], ctorParameters: () => [], propDecorators: { style: [{ type: i0.Input, args: [{ isSignal: true, alias: "style", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], formats: [{ type: i0.Input, args: [{ isSignal: true, alias: "formats", required: false }] }], modules: [{ type: i0.Input, args: [{ isSignal: true, alias: "modules", required: false }] }], bounds: [{ type: i0.Input, args: [{ isSignal: true, alias: "bounds", required: false }] }], scrollingContainer: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollingContainer", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], onEditorInit: [{ type: i0.Output, args: ["onInit"] }], onTextChange: [{ type: i0.Output, args: ["onTextChange"] }], onSelectionChange: [{ type: i0.Output, args: ["onSelectionChange"] }], onEditorChange: [{ type: i0.Output, args: ["onEditorChange"] }], onFocus: [{ type: i0.Output, args: ["onFocus"] }], onBlur: [{ type: i0.Output, args: ["onBlur"] }], toolbar: [{ type: i0.ContentChild, args: [i0.forwardRef(() => Header), { ...{ descendants: false }, isSignal: true }] }], headerTemplate: [{ type: i0.ContentChild, args: ['header', { ...{ descendants: false }, isSignal: true }] }] } }); class EditorModule { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: EditorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.6", ngImport: i0, type: EditorModule, imports: [Editor, SharedModule], exports: [Editor, SharedModule] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: EditorModule, imports: [Editor, SharedModule, SharedModule] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: EditorModule, decorators: [{ type: NgModule, args: [{ imports: [Editor, SharedModule], exports: [Editor, SharedModule] }] }] }); /** * Generated bundle index. Do not edit. */ export { EDITOR_VALUE_ACCESSOR, Editor, EditorClasses, EditorModule, EditorStyle }; //# sourceMappingURL=primeng-editor.mjs.map