UNPKG

ngx-quill

Version:

An angular (>= v2) component for the easy use of the QuillJS richt text editor.

742 lines (734 loc) 29.2 kB
import { __decorate, __metadata, __param } from 'tslib'; import { isPlatformServer, DOCUMENT, CommonModule } from '@angular/common'; import { InjectionToken, SecurityContext, Input, Output, EventEmitter, Component, ViewEncapsulation, forwardRef, Inject, PLATFORM_ID, ElementRef, Renderer2, NgZone, NgModule } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; var defaultModules = { toolbar: [ ['bold', 'italic', 'underline', 'strike'], ['blockquote', 'code-block'], [{ header: 1 }, { header: 2 }], [{ list: 'ordered' }, { list: 'bullet' }], [{ script: 'sub' }, { script: 'super' }], [{ indent: '-1' }, { indent: '+1' }], [{ direction: 'rtl' }], [{ size: ['small', false, 'large', 'huge'] }], [{ header: [1, 2, 3, 4, 5, 6, false] }], [ { color: [] }, { background: [] } ], [{ font: [] }], [{ align: [] }], ['clean'], ['link', 'image', 'video'] // link and image, video ] }; var QUILL_CONFIG_TOKEN = new InjectionToken('config'); // tslint:disable-next-line:variable-name var Quill = null; var getFormat = function (format, configFormat) { var passedFormat = format || configFormat; return passedFormat || 'html'; }; var ɵ0 = getFormat; var QuillEditorComponent = /** @class */ (function () { function QuillEditorComponent(elementRef, domSanitizer, doc, // tslint:disable-next-line:ban-types platformId, renderer, zone, config) { var _this = this; this.elementRef = elementRef; this.domSanitizer = domSanitizer; this.doc = doc; this.platformId = platformId; this.renderer = renderer; this.zone = zone; this.config = config; this.required = false; this.customToolbarPosition = 'top'; this.sanitize = false; this.styles = null; this.strict = true; this.customOptions = []; this.preserveWhitespace = false; this.onEditorCreated = new EventEmitter(); this.onEditorChanged = new EventEmitter(); this.onContentChanged = new EventEmitter(); this.onSelectionChanged = new EventEmitter(); this.onFocus = new EventEmitter(); this.onBlur = new EventEmitter(); this.disabled = false; // used to store initial value before ViewInit this.valueGetter = function (quillEditor, editorElement) { var html = editorElement.querySelector('.ql-editor').innerHTML; if (html === '<p><br></p>' || html === '<div><br><div>') { html = null; } var modelValue = html; var format = getFormat(_this.format, _this.config.format); if (format === 'text') { modelValue = quillEditor.getText(); } else if (format === 'object') { modelValue = quillEditor.getContents(); } else if (format === 'json') { try { modelValue = JSON.stringify(quillEditor.getContents()); } catch (e) { modelValue = quillEditor.getText(); } } return modelValue; }; this.valueSetter = function (quillEditor, value) { var format = getFormat(_this.format, _this.config.format); if (format === 'html') { if (_this.sanitize) { value = _this.domSanitizer.sanitize(SecurityContext.HTML, value); } return quillEditor.clipboard.convert(value); } else if (format === 'json') { try { return JSON.parse(value); } catch (e) { return [{ insert: value }]; } } return value; }; this.selectionChangeHandler = function (range, oldRange, source) { _this.zone.run(function () { if (range === null) { _this.onBlur.emit({ editor: _this.quillEditor, source: source }); } else if (oldRange === null) { _this.onFocus.emit({ editor: _this.quillEditor, source: source }); } _this.onSelectionChanged.emit({ editor: _this.quillEditor, oldRange: oldRange, range: range, source: source }); if (!range && _this.onModelTouched) { _this.onModelTouched(); } }); }; this.textChangeHandler = function (delta, oldDelta, source) { // only emit changes emitted by user interactions var text = _this.quillEditor.getText(); var content = _this.quillEditor.getContents(); var html = _this.editorElem.querySelector('.ql-editor').innerHTML; if (html === '<p><br></p>' || html === '<div><br><div>') { html = null; } _this.zone.run(function () { var trackChanges = _this.trackChanges || _this.config.trackChanges; if ((source === Quill.sources.USER || trackChanges && trackChanges === 'all') && _this.onModelChange) { _this.onModelChange(_this.valueGetter(_this.quillEditor, _this.editorElem)); } _this.onContentChanged.emit({ content: content, delta: delta, editor: _this.quillEditor, html: html, oldDelta: oldDelta, source: source, text: text }); }); }; this.editorChangeHandler = function (event, current, old, source) { // only emit changes emitted by user interactions if (event === 'text-change') { var text_1 = _this.quillEditor.getText(); var content_1 = _this.quillEditor.getContents(); var html_1 = _this.editorElem.querySelector('.ql-editor').innerHTML; if (html_1 === '<p><br></p>' || html_1 === '<div><br><div>') { html_1 = null; } _this.zone.run(function () { _this.onEditorChanged.emit({ content: content_1, delta: current, editor: _this.quillEditor, event: event, html: html_1, oldDelta: old, source: source, text: text_1 }); }); } else { _this.onEditorChanged.emit({ editor: _this.quillEditor, event: event, oldRange: old, range: current, source: source }); } }; } QuillEditorComponent_1 = QuillEditorComponent; // tslint:disable-next-line:no-empty QuillEditorComponent.prototype.onModelChange = function (_modelValue) { }; // tslint:disable-next-line:no-empty QuillEditorComponent.prototype.onModelTouched = function () { }; QuillEditorComponent.prototype.ngAfterViewInit = function () { var _this = this; if (isPlatformServer(this.platformId)) { return; } if (!Quill) { Quill = require('quill'); } this.elementRef.nativeElement.insertAdjacentHTML(this.customToolbarPosition === 'top' ? 'beforeend' : 'afterbegin', this.preserveWhitespace ? '<pre quill-editor-element></pre>' : '<div quill-editor-element></div>'); this.editorElem = this.elementRef.nativeElement.querySelector('[quill-editor-element]'); var toolbarElem = this.elementRef.nativeElement.querySelector('[quill-editor-toolbar]'); var modules = Object.assign({}, this.modules || (this.config.modules || defaultModules)); if (toolbarElem) { modules.toolbar = toolbarElem; } else if (modules.toolbar === undefined) { modules.toolbar = defaultModules.toolbar; } var placeholder = this.placeholder !== undefined ? this.placeholder : this.config.placeholder; if (placeholder === undefined) { placeholder = 'Insert text here ...'; } if (this.styles) { Object.keys(this.styles).forEach(function (key) { _this.renderer.setStyle(_this.editorElem, key, _this.styles[key]); }); } this.customOptions.forEach(function (customOption) { var newCustomOption = Quill.import(customOption.import); newCustomOption.whitelist = customOption.whitelist; Quill.register(newCustomOption, true); }); var bounds = this.bounds && this.bounds === 'self' ? this.editorElem : this.bounds; if (!bounds) { bounds = this.config.bounds ? this.config.bounds : this.doc.body; } var debug = this.debug; if (!debug && debug !== false && this.config.debug) { debug = this.config.debug; } var readOnly = this.readOnly; if (!readOnly && this.readOnly !== false) { readOnly = this.config.readOnly !== undefined ? this.config.readOnly : false; } var scrollingContainer = this.scrollingContainer; if (!scrollingContainer && this.scrollingContainer !== null) { scrollingContainer = this.config.scrollingContainer === null || this.config.scrollingContainer ? this.config.scrollingContainer : null; } var formats = this.formats; if (!formats && formats === undefined) { formats = this.config.formats ? Object.assign({}, this.config.formats) : (this.config.formats === null ? null : undefined); } this.quillEditor = new Quill(this.editorElem, { bounds: bounds, debug: debug, formats: formats, modules: modules, placeholder: placeholder, readOnly: readOnly, scrollingContainer: scrollingContainer, strict: this.strict, theme: this.theme || (this.config.theme ? this.config.theme : 'snow') }); if (this.content) { var format = getFormat(this.format, this.config.format); if (format === 'object') { this.quillEditor.setContents(this.content, 'silent'); } else if (format === 'text') { this.quillEditor.setText(this.content, 'silent'); } else if (format === 'json') { try { this.quillEditor.setContents(JSON.parse(this.content), 'silent'); } catch (e) { this.quillEditor.setText(this.content, 'silent'); } } else { if (this.sanitize) { this.content = this.domSanitizer.sanitize(SecurityContext.HTML, this.content); } var contents = this.quillEditor.clipboard.convert(this.content); this.quillEditor.setContents(contents, 'silent'); } this.quillEditor.history.clear(); } // initialize disabled status based on this.disabled as default value this.setDisabledState(); // triggered if selection or text changed this.quillEditor.on('editor-change', this.editorChangeHandler); // mark model as touched if editor lost focus this.quillEditor.on('selection-change', this.selectionChangeHandler); // update model if text changes this.quillEditor.on('text-change', this.textChangeHandler); // trigger created in a timeout to avoid changed models after checked // if you are using the editor api in created output to change the editor content setTimeout(function () { return _this.onEditorCreated.emit(_this.quillEditor); }); }; QuillEditorComponent.prototype.ngOnDestroy = function () { if (this.quillEditor) { this.quillEditor.off('selection-change', this.selectionChangeHandler); this.quillEditor.off('text-change', this.textChangeHandler); this.quillEditor.off('editor-change', this.editorChangeHandler); } }; QuillEditorComponent.prototype.ngOnChanges = function (changes) { var _this = this; if (!this.quillEditor) { return; } // tslint:disable:no-string-literal if (changes['readOnly']) { this.quillEditor.enable(!changes['readOnly'].currentValue); } if (changes['placeholder']) { this.quillEditor.root.dataset.placeholder = changes['placeholder'].currentValue; } if (changes['styles']) { var currentStyling = changes['styles'].currentValue; var previousStyling = changes['styles'].previousValue; if (previousStyling) { Object.keys(previousStyling).forEach(function (key) { _this.renderer.removeStyle(_this.editorElem, key); }); } if (currentStyling) { Object.keys(currentStyling).forEach(function (key) { _this.renderer.setStyle(_this.editorElem, key, _this.styles[key]); }); } } // tslint:enable:no-string-literal }; QuillEditorComponent.prototype.writeValue = function (currentValue) { this.content = currentValue; var format = getFormat(this.format, this.config.format); if (this.quillEditor) { if (currentValue) { if (format === 'text') { this.quillEditor.setText(currentValue); } else { this.quillEditor.setContents(this.valueSetter(this.quillEditor, this.content)); } return; } this.quillEditor.setText(''); } }; QuillEditorComponent.prototype.setDisabledState = function (isDisabled) { if (isDisabled === void 0) { isDisabled = this.disabled; } // store initial value to set appropriate disabled status after ViewInit this.disabled = isDisabled; if (this.quillEditor) { if (isDisabled) { this.quillEditor.disable(); this.renderer.setAttribute(this.elementRef.nativeElement, 'disabled', 'disabled'); } else { if (!this.readOnly) { this.quillEditor.enable(); } this.renderer.removeAttribute(this.elementRef.nativeElement, 'disabled'); } } }; QuillEditorComponent.prototype.registerOnChange = function (fn) { this.onModelChange = fn; }; QuillEditorComponent.prototype.registerOnTouched = function (fn) { this.onModelTouched = fn; }; QuillEditorComponent.prototype.validate = function () { if (!this.quillEditor) { return null; } var err = {}; var valid = true; var textLength = this.quillEditor.getText().trim().length; if (this.minLength && textLength && textLength < this.minLength) { err.minLengthError = { given: textLength, minLength: this.minLength }; valid = false; } if (this.maxLength && textLength > this.maxLength) { err.maxLengthError = { given: textLength, maxLength: this.maxLength }; valid = false; } if (this.required && !textLength) { err.requiredError = { empty: true }; valid = false; } return valid ? null : err; }; var QuillEditorComponent_1; __decorate([ Input(), __metadata("design:type", String) ], QuillEditorComponent.prototype, "format", void 0); __decorate([ Input(), __metadata("design:type", String) ], QuillEditorComponent.prototype, "theme", void 0); __decorate([ Input(), __metadata("design:type", Object) ], QuillEditorComponent.prototype, "modules", void 0); __decorate([ Input(), __metadata("design:type", Object) ], QuillEditorComponent.prototype, "debug", void 0); __decorate([ Input(), __metadata("design:type", Boolean) ], QuillEditorComponent.prototype, "readOnly", void 0); __decorate([ Input(), __metadata("design:type", String) ], QuillEditorComponent.prototype, "placeholder", void 0); __decorate([ Input(), __metadata("design:type", Number) ], QuillEditorComponent.prototype, "maxLength", void 0); __decorate([ Input(), __metadata("design:type", Number) ], QuillEditorComponent.prototype, "minLength", void 0); __decorate([ Input(), __metadata("design:type", Boolean) ], QuillEditorComponent.prototype, "required", void 0); __decorate([ Input(), __metadata("design:type", Array) ], QuillEditorComponent.prototype, "formats", void 0); __decorate([ Input(), __metadata("design:type", String) ], QuillEditorComponent.prototype, "customToolbarPosition", void 0); __decorate([ Input(), __metadata("design:type", Boolean) ], QuillEditorComponent.prototype, "sanitize", void 0); __decorate([ Input(), __metadata("design:type", Object) ], QuillEditorComponent.prototype, "styles", void 0); __decorate([ Input(), __metadata("design:type", Boolean) ], QuillEditorComponent.prototype, "strict", void 0); __decorate([ Input(), __metadata("design:type", Object) ], QuillEditorComponent.prototype, "scrollingContainer", void 0); __decorate([ Input(), __metadata("design:type", Object) ], QuillEditorComponent.prototype, "bounds", void 0); __decorate([ Input(), __metadata("design:type", Array) ], QuillEditorComponent.prototype, "customOptions", void 0); __decorate([ Input(), __metadata("design:type", String) ], QuillEditorComponent.prototype, "trackChanges", void 0); __decorate([ Input(), __metadata("design:type", Boolean) ], QuillEditorComponent.prototype, "preserveWhitespace", void 0); __decorate([ Output(), __metadata("design:type", EventEmitter) ], QuillEditorComponent.prototype, "onEditorCreated", void 0); __decorate([ Output(), __metadata("design:type", EventEmitter) ], QuillEditorComponent.prototype, "onEditorChanged", void 0); __decorate([ Output(), __metadata("design:type", EventEmitter) ], QuillEditorComponent.prototype, "onContentChanged", void 0); __decorate([ Output(), __metadata("design:type", EventEmitter) ], QuillEditorComponent.prototype, "onSelectionChanged", void 0); __decorate([ Output(), __metadata("design:type", EventEmitter) ], QuillEditorComponent.prototype, "onFocus", void 0); __decorate([ Output(), __metadata("design:type", EventEmitter) ], QuillEditorComponent.prototype, "onBlur", void 0); __decorate([ Input(), __metadata("design:type", Object) ], QuillEditorComponent.prototype, "valueGetter", void 0); __decorate([ Input(), __metadata("design:type", Object) ], QuillEditorComponent.prototype, "valueSetter", void 0); QuillEditorComponent = QuillEditorComponent_1 = __decorate([ Component({ encapsulation: ViewEncapsulation.None, providers: [ { multi: true, provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(function () { return QuillEditorComponent_1; }) }, { multi: true, provide: NG_VALIDATORS, useExisting: forwardRef(function () { return QuillEditorComponent_1; }) } ], selector: 'quill-editor', template: "\n <ng-content select=\"[quill-editor-toolbar]\"></ng-content>\n" }), __param(2, Inject(DOCUMENT)), __param(3, Inject(PLATFORM_ID)), __param(6, Inject(QUILL_CONFIG_TOKEN)), __metadata("design:paramtypes", [ElementRef, DomSanitizer, Object, Object, Renderer2, NgZone, Object]) ], QuillEditorComponent); return QuillEditorComponent; }()); var QuillViewHTMLComponent = /** @class */ (function () { function QuillViewHTMLComponent(sanitizer, config) { this.sanitizer = sanitizer; this.config = config; this.innerHTML = ''; this.themeClass = 'ql-snow'; this.content = ''; } QuillViewHTMLComponent.prototype.ngOnChanges = function (changes) { if (changes.theme) { var theme = changes.theme.currentValue || (this.config.theme ? this.config.theme : 'snow'); this.themeClass = "ql-" + theme + " ngx-quill-view-html"; } else if (!this.theme) { var theme = this.config.theme ? this.config.theme : 'snow'; this.themeClass = "ql-" + theme + " ngx-quill-view-html"; } if (changes.content) { this.innerHTML = this.sanitizer.bypassSecurityTrustHtml(changes.content.currentValue); } }; __decorate([ Input(), __metadata("design:type", String) ], QuillViewHTMLComponent.prototype, "content", void 0); __decorate([ Input(), __metadata("design:type", String) ], QuillViewHTMLComponent.prototype, "theme", void 0); QuillViewHTMLComponent = __decorate([ Component({ encapsulation: ViewEncapsulation.None, selector: 'quill-view-html', template: "\n <div class=\"ql-container\" [ngClass]=\"themeClass\">\n <div class=\"ql-editor\" [innerHTML]=\"innerHTML\">\n </div>\n </div>\n", styles: ["\n.ql-container.ngx-quill-view-html {\n border: 0;\n}\n"] }), __param(1, Inject(QUILL_CONFIG_TOKEN)), __metadata("design:paramtypes", [DomSanitizer, Object]) ], QuillViewHTMLComponent); return QuillViewHTMLComponent; }()); // tslint:disable-next-line:variable-name var Quill$1 = null; var getFormat$1 = function (format, configFormat) { var passedFormat = format || configFormat; return passedFormat || 'html'; }; var QuillViewComponent = /** @class */ (function () { function QuillViewComponent( // tslint:disable-next-line:ban-types platformId, config, renderer, elementRef) { var _this = this; this.platformId = platformId; this.config = config; this.renderer = renderer; this.elementRef = elementRef; this.strict = true; this.customOptions = []; this.preserveWhitespace = false; this.valueSetter = function (quillEditor, value) { var format = getFormat$1(_this.format, _this.config.format); var content = value; if (format === 'html' || format === 'text') { content = quillEditor.clipboard.convert(value); } else if (format === 'json') { try { content = JSON.parse(value); } catch (e) { content = [{ insert: value }]; } } quillEditor.setContents(content); }; } QuillViewComponent.prototype.ngOnChanges = function (changes) { if (!this.quillEditor) { return; } if (changes.content) { this.valueSetter(this.quillEditor, changes.content.currentValue); } }; QuillViewComponent.prototype.ngAfterViewInit = function () { if (isPlatformServer(this.platformId)) { return; } if (!Quill$1) { Quill$1 = require('quill'); } var modules = Object.assign({}, this.modules || (this.config.modules || defaultModules)); modules.toolbar = false; this.customOptions.forEach(function (customOption) { var newCustomOption = Quill$1.import(customOption.import); newCustomOption.whitelist = customOption.whitelist; Quill$1.register(newCustomOption, true); }); var debug = this.debug; if (!debug && debug !== false && this.config.debug) { debug = this.config.debug; } var formats = this.formats; if (!formats && formats === undefined) { formats = this.config.formats ? Object.assign({}, this.config.formats) : (this.config.formats === null ? null : undefined); } var theme = this.theme || (this.config.theme ? this.config.theme : 'snow'); this.elementRef.nativeElement.insertAdjacentHTML('afterbegin', this.preserveWhitespace ? '<pre quill-view-element></pre>' : '<div quill-view-element></div>'); this.editorElem = this.elementRef.nativeElement.querySelector('[quill-view-element]'); this.quillEditor = new Quill$1(this.editorElem, { debug: debug, formats: formats, modules: modules, readOnly: true, strict: this.strict, theme: theme }); this.renderer.addClass(this.editorElem, 'ngx-quill-view'); if (this.content) { this.valueSetter(this.quillEditor, this.content); } }; __decorate([ Input(), __metadata("design:type", String) ], QuillViewComponent.prototype, "format", void 0); __decorate([ Input(), __metadata("design:type", String) ], QuillViewComponent.prototype, "theme", void 0); __decorate([ Input(), __metadata("design:type", Object) ], QuillViewComponent.prototype, "modules", void 0); __decorate([ Input(), __metadata("design:type", Object) ], QuillViewComponent.prototype, "debug", void 0); __decorate([ Input(), __metadata("design:type", Array) ], QuillViewComponent.prototype, "formats", void 0); __decorate([ Input(), __metadata("design:type", Boolean) ], QuillViewComponent.prototype, "strict", void 0); __decorate([ Input(), __metadata("design:type", Object) ], QuillViewComponent.prototype, "content", void 0); __decorate([ Input(), __metadata("design:type", Array) ], QuillViewComponent.prototype, "customOptions", void 0); __decorate([ Input(), __metadata("design:type", Boolean) ], QuillViewComponent.prototype, "preserveWhitespace", void 0); QuillViewComponent = __decorate([ Component({ encapsulation: ViewEncapsulation.None, selector: 'quill-view', template: "\n", styles: ["\n.ql-container.ngx-quill-view {\n border: 0;\n}\n"] }), __param(0, Inject(PLATFORM_ID)), __param(1, Inject(QUILL_CONFIG_TOKEN)), __metadata("design:paramtypes", [Object, Object, Renderer2, ElementRef]) ], QuillViewComponent); return QuillViewComponent; }()); var QuillModule = /** @class */ (function () { function QuillModule() { } QuillModule_1 = QuillModule; QuillModule.forRoot = function (config) { return { ngModule: QuillModule_1, providers: [ { provide: QUILL_CONFIG_TOKEN, // tslint:disable-next-line:only-arrow-functions useValue: config || { modules: defaultModules } } ] }; }; var QuillModule_1; QuillModule = QuillModule_1 = __decorate([ NgModule({ declarations: [ QuillEditorComponent, QuillViewComponent, QuillViewHTMLComponent ], exports: [QuillEditorComponent, QuillViewComponent, QuillViewHTMLComponent], imports: [CommonModule], providers: [] }) ], QuillModule); return QuillModule; }()); export { QUILL_CONFIG_TOKEN, QuillEditorComponent, QuillModule, QuillViewComponent, QuillViewHTMLComponent, defaultModules, ɵ0 }; //# sourceMappingURL=ngx-quill.js.map