ngx-quill
Version:
Angular components for the easy use of the QuillJS richt text editor.
1 lines • 75.1 kB
Source Map (JSON)
{"version":3,"file":"ngx-quill.mjs","sources":["../../../projects/ngx-quill/src/lib/helpers.ts","../../../projects/ngx-quill/src/lib/quill.service.ts","../../../projects/ngx-quill/src/lib/quill-editor.component.ts","../../../projects/ngx-quill/src/lib/quill-view-html.component.ts","../../../projects/ngx-quill/src/lib/quill-view.component.ts","../../../projects/ngx-quill/src/lib/quill.module.ts","../../../projects/ngx-quill/src/public-api.ts","../../../projects/ngx-quill/src/ngx-quill.ts"],"sourcesContent":["import { QuillFormat } from 'ngx-quill/config'\nimport { Observable } from 'rxjs'\n\nexport const getFormat = (format?: QuillFormat, configFormat?: QuillFormat): QuillFormat => {\n const passedFormat = format || configFormat\n return passedFormat || 'html'\n}\n\nexport const raf$ = () => {\n return new Observable<void>(subscriber => {\n const rafId = requestAnimationFrame(() => {\n subscriber.next()\n subscriber.complete()\n })\n\n return () => cancelAnimationFrame(rafId)\n })\n}\n","import { DOCUMENT } from '@angular/common'\nimport { inject, Injectable } from '@angular/core'\nimport { defer, firstValueFrom, forkJoin, from, isObservable, Observable, of } from 'rxjs'\nimport { map, shareReplay, tap } from 'rxjs/operators'\n\nimport {\n CustomModule,\n defaultModules,\n QUILL_CONFIG_TOKEN,\n QuillConfig\n} from 'ngx-quill/config'\n\n@Injectable({\n providedIn: 'root',\n})\nexport class QuillService {\n readonly config = inject(QUILL_CONFIG_TOKEN) || { modules:defaultModules } as QuillConfig\n\n private document = inject(DOCUMENT)\n\n private Quill!: any\n\n private quill$: Observable<any> = defer(async () => {\n if (!this.Quill) {\n // Quill adds events listeners on import https://github.com/quilljs/quill/blob/develop/core/emitter.js#L8\n // We'd want to use the unpatched `addEventListener` method to have all event callbacks to be run outside of zone.\n // We don't know yet if the `zone.js` is used or not, just save the value to restore it back further.\n const maybePatchedAddEventListener = this.document.addEventListener\n // There're 2 types of Angular applications:\n // 1) zone-full (by default)\n // 2) zone-less\n // The developer can avoid importing the `zone.js` package and tells Angular that he/she is responsible for running\n // the change detection by himself. This is done by \"nooping\" the zone through `CompilerOptions` when bootstrapping\n // the root module. We fallback to `document.addEventListener` if `__zone_symbol__addEventListener` is not defined,\n // this means the `zone.js` is not imported.\n // The `__zone_symbol__addEventListener` is basically a native DOM API, which is not patched by zone.js, thus not even going\n // through the `zone.js` task lifecycle. You can also access the native DOM API as follows `target[Zone.__symbol__('methodName')]`.\n this.document.addEventListener =\n this.document['__zone_symbol__addEventListener'] ||\n this.document.addEventListener\n const quillImport = await import('quill')\n this.document.addEventListener = maybePatchedAddEventListener\n\n this.Quill = (\n // seems like esmodules have nested \"default\"\n (quillImport.default as any)?.default ?? quillImport.default ?? quillImport\n ) as any\n }\n\n // Only register custom options and modules once\n this.config.customOptions?.forEach((customOption) => {\n const newCustomOption = this.Quill.import(customOption.import)\n newCustomOption.whitelist = customOption.whitelist\n this.Quill.register(\n newCustomOption,\n true,\n this.config.suppressGlobalRegisterWarning\n )\n })\n\n return firstValueFrom(this.registerCustomModules(\n this.Quill,\n this.config.customModules,\n this.config.suppressGlobalRegisterWarning\n ))\n }).pipe(\n shareReplay({\n bufferSize: 1,\n refCount: false\n })\n )\n\n // A list of custom modules that have already been registered,\n // so we don’t need to await their implementation.\n private registeredModules = new Set<string>()\n\n getQuill() {\n return this.quill$\n }\n\n /** @internal */\n beforeRender(Quill: any, customModules: CustomModule[] | undefined, beforeRender = this.config.beforeRender) {\n // This function is called each time the editor needs to be rendered,\n // so it operates individually per component. If no custom module needs to be\n // registered and no `beforeRender` function is provided, it will emit\n // immediately and proceed with the rendering.\n const sources = [this.registerCustomModules(Quill, customModules)]\n if (beforeRender) {\n sources.push(from(beforeRender()))\n }\n return forkJoin(sources).pipe(map(() => Quill))\n }\n\n /** @internal */\n private registerCustomModules(\n Quill: any,\n customModules: CustomModule[] | undefined,\n suppressGlobalRegisterWarning?: boolean\n ) {\n if (!Array.isArray(customModules)) {\n return of(Quill)\n }\n\n const sources: Observable<unknown>[] = []\n\n for (const customModule of customModules) {\n const { path, implementation: maybeImplementation } = customModule\n\n // If the module is already registered, proceed to the next module...\n if (this.registeredModules.has(path)) {\n continue\n }\n\n this.registeredModules.add(path)\n\n if (isObservable(maybeImplementation)) {\n // If the implementation is an observable, we will wait for it to load and\n // then register it with Quill. The caller will wait until the module is registered.\n sources.push(maybeImplementation.pipe(\n tap((implementation) => {\n Quill.register(path, implementation, suppressGlobalRegisterWarning)\n })\n ))\n } else {\n Quill.register(path, maybeImplementation, suppressGlobalRegisterWarning)\n }\n }\n\n return sources.length > 0 ? forkJoin(sources).pipe(map(() => Quill)) : of(Quill)\n }\n}\n","import { DOCUMENT, isPlatformServer } from '@angular/common'\nimport { DomSanitizer } from '@angular/platform-browser'\n\nimport type QuillType from 'quill'\nimport type { QuillOptions } from 'quill'\nimport type DeltaType from 'quill-delta'\n\nimport {\n AfterViewInit,\n ChangeDetectorRef,\n Component,\n DestroyRef,\n Directive,\n ElementRef,\n EventEmitter,\n forwardRef,\n inject,\n input,\n NgZone,\n OnChanges,\n OnDestroy,\n OnInit,\n Output,\n PLATFORM_ID,\n Renderer2,\n SecurityContext,\n signal,\n SimpleChanges,\n ViewEncapsulation\n} from '@angular/core'\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop'\nimport { fromEvent, Subscription } from 'rxjs'\nimport { debounceTime, mergeMap } from 'rxjs/operators'\n\nimport { ControlValueAccessor, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator } from '@angular/forms'\n\nimport { CustomModule, CustomOption, defaultModules, QuillBeforeRender, QuillModules } from 'ngx-quill/config'\n\nimport type History from 'quill/modules/history'\nimport type Toolbar from 'quill/modules/toolbar'\nimport { getFormat, raf$ } from './helpers'\nimport { QuillService } from './quill.service'\n\nexport interface Range {\n index: number\n length: number\n}\n\nexport interface ContentChange {\n content: DeltaType\n delta: DeltaType\n editor: QuillType\n html: string | null\n oldDelta: DeltaType\n source: string\n text: string\n}\n\nexport interface SelectionChange {\n editor: QuillType\n oldRange: Range | null\n range: Range | null\n source: string\n}\n\nexport interface Blur {\n editor: QuillType\n source: string\n}\n\nexport interface Focus {\n editor: QuillType\n source: string\n}\n\nexport type EditorChangeContent = ContentChange & { event: 'text-change' }\nexport type EditorChangeSelection = SelectionChange & { event: 'selection-change' }\n\n@Directive()\nexport abstract class QuillEditorBase implements AfterViewInit, ControlValueAccessor, OnChanges, OnInit, OnDestroy, Validator {\n readonly format = input<'object' | 'html' | 'text' | 'json' | undefined>(\n undefined\n )\n readonly theme = input<string | undefined>(undefined)\n readonly modules = input<QuillModules | undefined>(undefined)\n readonly debug = input<'warn' | 'log' | 'error' | false>(false)\n readonly readOnly = input<boolean | undefined>(false)\n readonly placeholder = input<string | undefined>(undefined)\n readonly maxLength = input<number | undefined>(undefined)\n readonly minLength = input<number | undefined>(undefined)\n readonly required = input(false)\n readonly formats = input<string[] | null | undefined>(undefined)\n readonly customToolbarPosition = input<'top' | 'bottom'>('top')\n readonly sanitize = input<boolean | undefined>(undefined)\n readonly beforeRender = input<QuillBeforeRender>(undefined)\n readonly styles = input<any>(null)\n readonly registry = input<QuillOptions['registry']>(\n undefined\n )\n readonly bounds = input<HTMLElement | string | undefined>(undefined)\n readonly customOptions = input<CustomOption[]>([])\n readonly customModules = input<CustomModule[]>([])\n readonly trackChanges = input<'user' | 'all' | undefined>(undefined)\n readonly classes = input<string | undefined>(undefined)\n readonly trimOnValidation = input(false)\n readonly linkPlaceholder = input<string | undefined>(undefined)\n readonly compareValues = input(false)\n readonly filterNull = input(false)\n readonly debounceTime = input<number | undefined>(undefined)\n /*\n https://github.com/KillerCodeMonkey/ngx-quill/issues/1257 - fix null value set\n\n provide default empty value\n by default null\n\n e.g. defaultEmptyValue=\"\" - empty string\n\n <quill-editor\n defaultEmptyValue=\"\"\n formControlName=\"message\"\n ></quill-editor>\n */\n readonly defaultEmptyValue = input<any>(null)\n\n @Output() onEditorCreated = new EventEmitter<QuillType>()\n @Output() onEditorChanged = new EventEmitter<EditorChangeContent | EditorChangeSelection>()\n @Output() onContentChanged = new EventEmitter<ContentChange>()\n @Output() onSelectionChanged = new EventEmitter<SelectionChange>()\n @Output() onFocus = new EventEmitter<Focus>()\n @Output() onBlur = new EventEmitter<Blur>()\n @Output() onNativeFocus = new EventEmitter<Focus>()\n @Output() onNativeBlur = new EventEmitter<Blur>()\n\n quillEditor!: QuillType\n editorElem!: HTMLElement\n content: any\n disabled = false // used to store initial value before ViewInit\n\n readonly toolbarPosition = signal('top')\n\n onModelChange: (modelValue?: any) => void\n onModelTouched: () => void\n onValidatorChanged: () => void\n\n private subscription: Subscription | null = null\n private quillSubscription: Subscription | null = null\n\n private elementRef = inject(ElementRef)\n private document = inject(DOCUMENT)\n\n private cd = inject(ChangeDetectorRef)\n private domSanitizer = inject(DomSanitizer)\n private platformId = inject<string>(PLATFORM_ID)\n private renderer = inject(Renderer2)\n private zone = inject(NgZone)\n private service = inject(QuillService)\n private destroyRef = inject(DestroyRef)\n\n static normalizeClassNames(classes: string): string[] {\n const classList = classes.trim().split(' ')\n return classList.reduce((prev: string[], cur: string) => {\n const trimmed = cur.trim()\n if (trimmed) {\n prev.push(trimmed)\n }\n\n return prev\n }, [])\n }\n\n valueGetter = input((quillEditor: QuillType): string | any => {\n let html: string | null = quillEditor.getSemanticHTML()\n if (this.isEmptyValue(html)) {\n html = this.defaultEmptyValue()\n }\n let modelValue: string | DeltaType | null = html\n const format = getFormat(this.format(), this.service.config.format)\n\n if (format === 'text') {\n modelValue = quillEditor.getText()\n } else if (format === 'object') {\n modelValue = quillEditor.getContents()\n } else if (format === 'json') {\n try {\n modelValue = JSON.stringify(quillEditor.getContents())\n } catch {\n modelValue = quillEditor.getText()\n }\n }\n\n return modelValue\n })\n\n valueSetter = input((quillEditor: QuillType, value: any): any => {\n const format = getFormat(this.format(), this.service.config.format)\n if (format === 'html') {\n const sanitize = [true, false].includes(this.sanitize()) ? this.sanitize() : (this.service.config.sanitize || false)\n if (sanitize) {\n value = this.domSanitizer.sanitize(SecurityContext.HTML, value)\n }\n return quillEditor.clipboard.convert({ html: value })\n } else if (format === 'json') {\n try {\n return JSON.parse(value)\n } catch {\n return [{ insert: value }]\n }\n }\n\n return value\n })\n\n ngOnInit() {\n this.toolbarPosition.set(this.customToolbarPosition())\n }\n\n ngAfterViewInit() {\n if (isPlatformServer(this.platformId)) {\n return\n }\n\n // The `quill-editor` component might be destroyed before the `quill` chunk is loaded and its code is executed\n // this will lead to runtime exceptions, since the code will be executed on DOM nodes that don't exist within the tree.\n\n this.quillSubscription = this.service.getQuill().pipe(\n mergeMap((Quill) => this.service.beforeRender(Quill, this.customModules(), this.beforeRender()))\n ).subscribe(Quill => {\n this.editorElem = this.elementRef.nativeElement.querySelector(\n '[quill-editor-element]'\n )\n\n const toolbarElem = this.elementRef.nativeElement.querySelector(\n '[quill-editor-toolbar]'\n )\n const modules = Object.assign({}, this.modules() || this.service.config.modules)\n\n if (toolbarElem) {\n modules.toolbar = toolbarElem\n } else if (modules.toolbar === undefined) {\n modules.toolbar = defaultModules.toolbar\n }\n\n let placeholder = this.placeholder() !== undefined ? this.placeholder() : this.service.config.placeholder\n if (placeholder === undefined) {\n placeholder = 'Insert text here ...'\n }\n\n const styles = this.styles()\n if (styles) {\n Object.keys(styles).forEach((key: string) => {\n this.renderer.setStyle(this.editorElem, key, styles[key])\n })\n }\n\n if (this.classes()) {\n this.addClasses(this.classes())\n }\n\n this.customOptions().forEach((customOption) => {\n const newCustomOption = Quill.import(customOption.import)\n newCustomOption.whitelist = customOption.whitelist\n Quill.register(newCustomOption, true)\n })\n\n let bounds = this.bounds() && this.bounds() === 'self' ? this.editorElem : this.bounds()\n if (!bounds) {\n bounds = this.service.config.bounds ? this.service.config.bounds : this.document.body\n }\n\n let debug = this.debug()\n if (!debug && debug !== false && this.service.config.debug) {\n debug = this.service.config.debug\n }\n\n let readOnly = this.readOnly()\n if (!readOnly && this.readOnly() !== false) {\n readOnly = this.service.config.readOnly !== undefined ? this.service.config.readOnly : false\n }\n\n let formats = this.formats()\n if (!formats && formats === undefined) {\n formats = this.service.config.formats ? [...this.service.config.formats] : (this.service.config.formats === null ? null : undefined)\n }\n\n this.zone.runOutsideAngular(() => {\n this.quillEditor = new Quill(this.editorElem, {\n bounds,\n debug,\n formats,\n modules,\n placeholder,\n readOnly,\n registry: this.registry(),\n theme: this.theme() || (this.service.config.theme ? this.service.config.theme : 'snow')\n })\n\n if (this.onNativeBlur.observed) {\n // https://github.com/quilljs/quill/issues/2186#issuecomment-533401328\n fromEvent(this.quillEditor.scroll.domNode, 'blur').pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.onNativeBlur.next({\n editor: this.quillEditor,\n source: 'dom'\n }))\n // https://github.com/quilljs/quill/issues/2186#issuecomment-803257538\n const toolbar = this.quillEditor.getModule('toolbar') as Toolbar\n if (toolbar.container) {\n fromEvent(toolbar.container, 'mousedown').pipe(takeUntilDestroyed(this.destroyRef)).subscribe(e => e.preventDefault())\n }\n }\n\n if (this.onNativeFocus.observed) {\n fromEvent(this.quillEditor.scroll.domNode, 'focus').pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.onNativeFocus.next({\n editor: this.quillEditor,\n source: 'dom'\n }))\n }\n\n // Set optional link placeholder, Quill has no native API for it so using workaround\n if (this.linkPlaceholder()) {\n const tooltip = (this.quillEditor as any)?.theme?.tooltip\n const input = tooltip?.root?.querySelector('input[data-link]')\n if (input?.dataset) {\n input.dataset.link = this.linkPlaceholder()\n }\n }\n })\n\n if (this.content) {\n const format = getFormat(this.format(), this.service.config.format)\n\n if (format === 'text') {\n this.quillEditor.setText(this.content, 'silent')\n } else {\n const valueSetter = this.valueSetter()\n const newValue = valueSetter(this.quillEditor, this.content)\n this.quillEditor.setContents(newValue, 'silent')\n }\n\n const history = this.quillEditor.getModule('history') as History\n history.clear()\n }\n\n // initialize disabled status based on this.disabled as default value\n this.setDisabledState()\n\n this.addQuillEventListeners()\n\n // The `requestAnimationFrame` triggers change detection. There's no sense to invoke the `requestAnimationFrame` if anyone is\n // listening to the `onEditorCreated` event inside the template, for instance `<quill-view (onEditorCreated)=\"...\">`.\n if (!this.onEditorCreated.observed && !this.onValidatorChanged) {\n return\n }\n\n // The `requestAnimationFrame` will trigger change detection and `onEditorCreated` will also call `markDirty()`\n // internally, since Angular wraps template event listeners into `listener` instruction. We're using the `requestAnimationFrame`\n // to prevent the frame drop and avoid `ExpressionChangedAfterItHasBeenCheckedError` error.\n raf$().pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n if (this.onValidatorChanged) {\n this.onValidatorChanged()\n }\n this.onEditorCreated.emit(this.quillEditor)\n })\n })\n }\n\n selectionChangeHandler = (range: Range | null, oldRange: Range | null, source: string) => {\n const trackChanges = this.trackChanges() || this.service.config.trackChanges\n const shouldTriggerOnModelTouched = !range && !!this.onModelTouched && (source === 'user' || trackChanges && trackChanges === 'all')\n\n // only emit changes when there's any listener\n if (!this.onBlur.observed &&\n !this.onFocus.observed &&\n !this.onSelectionChanged.observed &&\n !shouldTriggerOnModelTouched) {\n return\n }\n\n this.zone.run(() => {\n if (range === null) {\n this.onBlur.emit({\n editor: this.quillEditor,\n source\n })\n } else if (oldRange === null) {\n this.onFocus.emit({\n editor: this.quillEditor,\n source\n })\n }\n\n this.onSelectionChanged.emit({\n editor: this.quillEditor,\n oldRange,\n range,\n source\n })\n\n if (shouldTriggerOnModelTouched) {\n this.onModelTouched()\n }\n\n this.cd.markForCheck()\n })\n }\n\n textChangeHandler = (delta: DeltaType, oldDelta: DeltaType, source: string): void => {\n // only emit changes emitted by user interactions\n const text = this.quillEditor.getText()\n const content = this.quillEditor.getContents()\n\n let html: string | null = this.quillEditor.getSemanticHTML()\n if (this.isEmptyValue(html)) {\n html = this.defaultEmptyValue()\n }\n\n const trackChanges = this.trackChanges() || this.service.config.trackChanges\n const shouldTriggerOnModelChange = (source === 'user' || trackChanges && trackChanges === 'all') && !!this.onModelChange\n\n // only emit changes when there's any listener\n if (!this.onContentChanged.observed && !shouldTriggerOnModelChange) {\n return\n }\n\n this.zone.run(() => {\n if (shouldTriggerOnModelChange) {\n const valueGetter = this.valueGetter()\n this.onModelChange(\n valueGetter(this.quillEditor)\n )\n }\n\n this.onContentChanged.emit({\n content,\n delta,\n editor: this.quillEditor,\n html,\n oldDelta,\n source,\n text\n })\n\n this.cd.markForCheck()\n })\n }\n\n editorChangeHandler = (\n event: 'text-change' | 'selection-change',\n current: any | Range | null, old: any | Range | null, source: string\n ): void => {\n // only emit changes when there's any listener\n if (!this.onEditorChanged.observed) {\n return\n }\n\n // only emit changes emitted by user interactions\n if (event === 'text-change') {\n const text = this.quillEditor.getText()\n const content = this.quillEditor.getContents()\n\n let html: string | null = this.quillEditor.getSemanticHTML()\n if (this.isEmptyValue(html)) {\n html = this.defaultEmptyValue()\n }\n\n this.zone.run(() => {\n this.onEditorChanged.emit({\n content,\n delta: current,\n editor: this.quillEditor,\n event,\n html,\n oldDelta: old,\n source,\n text\n })\n\n this.cd.markForCheck()\n })\n } else {\n this.zone.run(() => {\n this.onEditorChanged.emit({\n editor: this.quillEditor,\n event,\n oldRange: old,\n range: current,\n source\n })\n\n this.cd.markForCheck()\n })\n }\n }\n\n ngOnDestroy() {\n this.dispose()\n\n this.quillSubscription?.unsubscribe()\n this.quillSubscription = null\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (!this.quillEditor) {\n return\n }\n if (changes.readOnly) {\n this.quillEditor.enable(!changes.readOnly.currentValue)\n }\n if (changes.placeholder) {\n this.quillEditor.root.dataset.placeholder =\n changes.placeholder.currentValue\n }\n if (changes.styles) {\n const currentStyling = changes.styles.currentValue\n const previousStyling = changes.styles.previousValue\n\n if (previousStyling) {\n Object.keys(previousStyling).forEach((key: string) => {\n this.renderer.removeStyle(this.editorElem, key)\n })\n }\n if (currentStyling) {\n Object.keys(currentStyling).forEach((key: string) => {\n this.renderer.setStyle(this.editorElem, key, this.styles()[key])\n })\n }\n }\n if (changes.classes) {\n const currentClasses = changes.classes.currentValue\n const previousClasses = changes.classes.previousValue\n\n if (previousClasses) {\n this.removeClasses(previousClasses)\n }\n\n if (currentClasses) {\n this.addClasses(currentClasses)\n }\n }\n // We'd want to re-apply event listeners if the `debounceTime` binding changes to apply the\n // `debounceTime` operator or vice-versa remove it.\n if (changes.debounceTime) {\n this.addQuillEventListeners()\n }\n }\n\n addClasses(classList: string): void {\n QuillEditorBase.normalizeClassNames(classList).forEach((c: string) => {\n this.renderer.addClass(this.editorElem, c)\n })\n }\n\n removeClasses(classList: string): void {\n QuillEditorBase.normalizeClassNames(classList).forEach((c: string) => {\n this.renderer.removeClass(this.editorElem, c)\n })\n }\n\n writeValue(currentValue: any) {\n\n // optional fix for https://github.com/angular/angular/issues/14988\n if (this.filterNull() && currentValue === null) {\n return\n }\n\n this.content = currentValue\n\n if (!this.quillEditor) {\n return\n }\n\n const format = getFormat(this.format(), this.service.config.format)\n const valueSetter = this.valueSetter()\n const newValue = valueSetter(this.quillEditor, currentValue)\n\n if (this.compareValues()) {\n const currentEditorValue = this.quillEditor.getContents()\n if (JSON.stringify(currentEditorValue) === JSON.stringify(newValue)) {\n return\n }\n }\n\n if (currentValue) {\n if (format === 'text') {\n this.quillEditor.setText(currentValue)\n } else {\n this.quillEditor.setContents(newValue)\n }\n return\n }\n this.quillEditor.setText('')\n\n }\n\n setDisabledState(isDisabled: boolean = this.disabled): void {\n // store initial value to set appropriate disabled status after ViewInit\n this.disabled = isDisabled\n if (this.quillEditor) {\n if (isDisabled) {\n this.quillEditor.disable()\n this.renderer.setAttribute(this.elementRef.nativeElement, 'disabled', 'disabled')\n } else {\n if (!this.readOnly()) {\n this.quillEditor.enable()\n }\n this.renderer.removeAttribute(this.elementRef.nativeElement, 'disabled')\n }\n }\n }\n\n registerOnChange(fn: (modelValue: any) => void): void {\n this.onModelChange = fn\n }\n\n registerOnTouched(fn: () => void): void {\n this.onModelTouched = fn\n }\n\n registerOnValidatorChange(fn: () => void) {\n this.onValidatorChanged = fn\n }\n\n validate() {\n if (!this.quillEditor) {\n return null\n }\n\n const err: {\n minLengthError?: {\n given: number\n minLength: number\n }\n maxLengthError?: {\n given: number\n maxLength: number\n }\n requiredError?: { empty: boolean }\n } = {}\n let valid = true\n\n const text = this.quillEditor.getText()\n // trim text if wanted + handle special case that an empty editor contains a new line\n const textLength = this.trimOnValidation() ? text.trim().length : (text.length === 1 && text.trim().length === 0 ? 0 : text.length - 1)\n const deltaOperations = this.quillEditor.getContents().ops\n const onlyEmptyOperation = !!deltaOperations && deltaOperations.length === 1 && ['\\n', ''].includes(deltaOperations[0].insert?.toString())\n\n if (this.minLength() && textLength && textLength < this.minLength()) {\n err.minLengthError = {\n given: textLength,\n minLength: this.minLength()\n }\n\n valid = false\n }\n\n if (this.maxLength() && textLength > this.maxLength()) {\n err.maxLengthError = {\n given: textLength,\n maxLength: this.maxLength()\n }\n\n valid = false\n }\n\n if (this.required() && !textLength && onlyEmptyOperation) {\n err.requiredError = {\n empty: true\n }\n\n valid = false\n }\n\n return valid ? null : err\n }\n\n private addQuillEventListeners(): void {\n this.dispose()\n\n // We have to enter the `<root>` zone when adding event listeners, so `debounceTime` will spawn the\n // `AsyncAction` there w/o triggering change detections. We still re-enter the Angular's zone through\n // `zone.run` when we emit an event to the parent component.\n this.zone.runOutsideAngular(() => {\n this.subscription = new Subscription()\n\n this.subscription.add(\n // mark model as touched if editor lost focus\n fromEvent(this.quillEditor, 'selection-change').subscribe(\n ([range, oldRange, source]) => {\n this.selectionChangeHandler(range as any, oldRange as any, source)\n }\n )\n )\n\n // The `fromEvent` supports passing JQuery-style event targets, the editor has `on` and `off` methods which\n // will be invoked upon subscription and teardown.\n let textChange$ = fromEvent(this.quillEditor, 'text-change')\n let editorChange$ = fromEvent(this.quillEditor, 'editor-change')\n\n if (typeof this.debounceTime() === 'number') {\n textChange$ = textChange$.pipe(debounceTime(this.debounceTime()))\n editorChange$ = editorChange$.pipe(debounceTime(this.debounceTime()))\n }\n\n this.subscription.add(\n // update model if text changes\n textChange$.subscribe(([delta, oldDelta, source]) => {\n this.textChangeHandler(delta as any, oldDelta as any, source)\n })\n )\n\n this.subscription.add(\n // triggered if selection or text changed\n editorChange$.subscribe(([event, current, old, source]) => {\n this.editorChangeHandler(event as 'text-change' | 'selection-change', current, old, source)\n })\n )\n })\n }\n\n private dispose(): void {\n if (this.subscription !== null) {\n this.subscription.unsubscribe()\n this.subscription = null\n }\n }\n\n private isEmptyValue(html: string | null) {\n return html === '<p></p>' || html === '<div></div>' || html === '<p><br></p>' || html === '<div><br></div>'\n }\n}\n\n@Component({\n encapsulation: ViewEncapsulation.Emulated,\n providers: [\n {\n multi: true,\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => QuillEditorComponent)\n },\n {\n multi: true,\n provide: NG_VALIDATORS,\n useExisting: forwardRef(() => QuillEditorComponent)\n }\n ],\n selector: 'quill-editor',\n template: `\n @if (toolbarPosition() !== 'top') {\n <div quill-editor-element></div>\n }\n\n <ng-content select=\"[above-quill-editor-toolbar]\"></ng-content>\n <ng-content select=\"[quill-editor-toolbar]\"></ng-content>\n <ng-content select=\"[below-quill-editor-toolbar]\"></ng-content>\n\n @if (toolbarPosition() === 'top') {\n <div quill-editor-element></div>\n }\n `,\n styles: [\n `\n :host {\n display: inline-block;\n }\n `\n ]\n})\nexport class QuillEditorComponent extends QuillEditorBase { }\n","import { DomSanitizer, SafeHtml } from '@angular/platform-browser'\nimport { QuillService } from './quill.service'\n\nimport {\n Component,\n OnChanges,\n SimpleChanges,\n ViewEncapsulation,\n input,\n signal\n} from '@angular/core'\n\n@Component({\n encapsulation: ViewEncapsulation.None,\n selector: 'quill-view-html',\n styles: [`\n.ql-container.ngx-quill-view-html {\n border: 0;\n}\n`],\n template: `\n <div class=\"ql-container\" [class]=\"themeClass()\">\n <div class=\"ql-editor\" [innerHTML]=\"innerHTML()\">\n </div>\n </div>\n`\n})\nexport class QuillViewHTMLComponent implements OnChanges {\n readonly content = input('')\n readonly theme = input<string | undefined>(undefined)\n readonly sanitize = input<boolean | undefined>(undefined)\n\n readonly innerHTML = signal<SafeHtml>('')\n readonly themeClass = signal('ql-snow')\n\n constructor(\n private sanitizer: DomSanitizer,\n protected service: QuillService\n ) {}\n\n ngOnChanges(changes: SimpleChanges) {\n if (changes.theme) {\n const theme = changes.theme.currentValue || (this.service.config.theme ? this.service.config.theme : 'snow')\n this.themeClass.set(`ql-${theme} ngx-quill-view-html`)\n } else if (!this.theme()) {\n const theme = this.service.config.theme ? this.service.config.theme : 'snow'\n this.themeClass.set(`ql-${theme} ngx-quill-view-html`)\n }\n if (changes.content) {\n const content = changes.content.currentValue\n const sanitize = [true, false].includes(this.sanitize()) ? this.sanitize() : (this.service.config.sanitize || false)\n const innerHTML = sanitize ? content : this.sanitizer.bypassSecurityTrustHtml(content)\n this.innerHTML.set(innerHTML)\n }\n }\n}\n","import { isPlatformServer } from '@angular/common'\nimport type QuillType from 'quill'\n\nimport {\n AfterViewInit,\n Component,\n DestroyRef,\n ElementRef,\n EventEmitter,\n Inject,\n NgZone,\n OnChanges,\n OnDestroy,\n Output,\n PLATFORM_ID,\n Renderer2,\n SecurityContext,\n SimpleChanges,\n ViewEncapsulation,\n inject,\n input\n} from '@angular/core'\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop'\nimport { DomSanitizer } from '@angular/platform-browser'\nimport type { Subscription } from 'rxjs'\nimport { mergeMap } from 'rxjs/operators'\n\nimport { CustomModule, CustomOption, QuillBeforeRender, QuillModules } from 'ngx-quill/config'\n\nimport { getFormat, raf$ } from './helpers'\nimport { QuillService } from './quill.service'\n\n@Component({\n encapsulation: ViewEncapsulation.None,\n selector: 'quill-view',\n styles: [`\n.ql-container.ngx-quill-view {\n border: 0;\n}\n`],\n template: `\n <div quill-view-element></div>\n`,\n})\nexport class QuillViewComponent implements AfterViewInit, OnChanges, OnDestroy {\n readonly format = input<'object' | 'html' | 'text' | 'json' | undefined>(\n undefined\n )\n readonly theme = input<string | undefined>(undefined)\n readonly modules = input<QuillModules | undefined>(undefined)\n readonly debug = input<'warn' | 'log' | 'error' | false>(false)\n readonly formats = input<string[] | null | undefined>(undefined)\n readonly sanitize = input<boolean | undefined>(undefined)\n readonly beforeRender = input<QuillBeforeRender>()\n readonly strict = input(true)\n readonly content = input<any>()\n readonly customModules = input<CustomModule[]>([])\n readonly customOptions = input<CustomOption[]>([])\n\n @Output() onEditorCreated = new EventEmitter<any>()\n\n quillEditor!: QuillType\n editorElem!: HTMLElement\n\n private quillSubscription: Subscription | null = null\n\n private destroyRef = inject(DestroyRef)\n\n constructor(\n public elementRef: ElementRef,\n protected renderer: Renderer2,\n protected zone: NgZone,\n protected service: QuillService,\n protected domSanitizer: DomSanitizer,\n @Inject(PLATFORM_ID) protected platformId: any,\n ) { }\n\n valueSetter = (quillEditor: QuillType, value: any): any => {\n const format = getFormat(this.format(), this.service.config.format)\n let content = value\n if (format === 'text') {\n quillEditor.setText(content)\n } else {\n if (format === 'html') {\n const sanitize = [true, false].includes(this.sanitize()) ? this.sanitize() : (this.service.config.sanitize || false)\n if (sanitize) {\n value = this.domSanitizer.sanitize(SecurityContext.HTML, value)\n }\n content = quillEditor.clipboard.convert({ html: value })\n } else if (format === 'json') {\n try {\n content = JSON.parse(value)\n } catch {\n content = [{ insert: value }]\n }\n }\n quillEditor.setContents(content)\n }\n }\n\n ngOnChanges(changes: SimpleChanges) {\n if (!this.quillEditor) {\n return\n }\n if (changes.content) {\n this.valueSetter(this.quillEditor, changes.content.currentValue)\n }\n }\n\n ngAfterViewInit() {\n if (isPlatformServer(this.platformId)) {\n return\n }\n\n this.quillSubscription = this.service.getQuill().pipe(\n mergeMap((Quill) => this.service.beforeRender(Quill, this.customModules(), this.beforeRender()))\n ).subscribe(Quill => {\n const modules = Object.assign({}, this.modules() || this.service.config.modules)\n modules.toolbar = false\n\n this.customOptions().forEach((customOption) => {\n const newCustomOption = Quill.import(customOption.import)\n newCustomOption.whitelist = customOption.whitelist\n Quill.register(newCustomOption, true)\n })\n\n let debug = this.debug()\n if (!debug && debug !== false && this.service.config.debug) {\n debug = this.service.config.debug\n }\n\n let formats = this.formats()\n if (!formats && formats === undefined) {\n formats = this.service.config.formats ? [...this.service.config.formats] : (this.service.config.formats === null ? null : undefined)\n }\n const theme = this.theme() || (this.service.config.theme ? this.service.config.theme : 'snow')\n\n this.editorElem = this.elementRef.nativeElement.querySelector(\n '[quill-view-element]'\n ) as HTMLElement\n\n this.zone.runOutsideAngular(() => {\n this.quillEditor = new Quill(this.editorElem, {\n debug,\n formats,\n modules,\n readOnly: true,\n strict: this.strict(),\n theme\n })\n })\n\n this.renderer.addClass(this.editorElem, 'ngx-quill-view')\n\n if (this.content()) {\n this.valueSetter(this.quillEditor, this.content())\n }\n\n // The `requestAnimationFrame` triggers change detection. There's no sense to invoke the `requestAnimationFrame` if anyone is\n // listening to the `onEditorCreated` event inside the template, for instance `<quill-view (onEditorCreated)=\"...\">`.\n if (!this.onEditorCreated.observed) {\n return\n }\n\n // The `requestAnimationFrame` will trigger change detection and `onEditorCreated` will also call `markDirty()`\n // internally, since Angular wraps template event listeners into `listener` instruction. We're using the `requestAnimationFrame`\n // to prevent the frame drop and avoid `ExpressionChangedAfterItHasBeenCheckedError` error.\n raf$().pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n this.onEditorCreated.emit(this.quillEditor)\n })\n })\n }\n\n ngOnDestroy(): void {\n this.quillSubscription?.unsubscribe()\n this.quillSubscription = null\n }\n}\n","import { ModuleWithProviders, NgModule } from '@angular/core'\n\nimport { QUILL_CONFIG_TOKEN, QuillConfig } from 'ngx-quill/config'\n\nimport { QuillEditorComponent } from './quill-editor.component'\nimport { QuillViewHTMLComponent } from './quill-view-html.component'\nimport { QuillViewComponent } from './quill-view.component'\n\n@NgModule({\n imports: [QuillEditorComponent, QuillViewComponent, QuillViewHTMLComponent],\n exports: [QuillEditorComponent, QuillViewComponent, QuillViewHTMLComponent],\n})\nexport class QuillModule {\n static forRoot(config?: QuillConfig): ModuleWithProviders<QuillModule> {\n return {\n ngModule: QuillModule,\n providers: [\n {\n provide: QUILL_CONFIG_TOKEN,\n useValue: config\n }\n ]\n }\n }\n}\n","/*\n * Public API Surface of ngx-quill\n */\n\n// Re-export everything from the secondary entry-point so we can be backwards-compatible\n// and don't introduce breaking changes for consumers.\nexport * from 'ngx-quill/config'\n\nexport * from './lib/quill.module'\nexport * from './lib/quill.service'\nexport * from './lib/quill-editor.component'\nexport * from './lib/quill-view.component'\nexport * from './lib/quill-view-html.component'\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i2.QuillService"],"mappings":"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