diff --git a/packages/ngx-widgets/src/app/area-size/area-size.directive.spec.ts b/packages/ngx-widgets/src/app/area-size/area-size.directive.spec.ts new file mode 100644 index 000000000..d1d87a0ef --- /dev/null +++ b/packages/ngx-widgets/src/app/area-size/area-size.directive.spec.ts @@ -0,0 +1,47 @@ +import { Component } from '@angular/core'; +import { TestBed, ComponentFixture } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { AreaSizeDirective } from './area-size.directive'; + +@Component({ + selector: 'my-test-component', + template: '', +}) +class TestComponent { + content: string = ''; +} + +describe('area-size directive: ', () => { + let component: TestComponent; + let fixture: ComponentFixture; + let textarea: HTMLTextAreaElement; + let autosize: any; + + beforeEach(async () => { + TestBed.configureTestingModule({ + declarations: [TestComponent, AreaSizeDirective], + }); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + component = fixture.componentInstance; + textarea = fixture.nativeElement.querySelector('textarea'); + autosize = fixture.debugElement.query(By.directive(AreaSizeDirective)); + }); + + it('textarea should have equal content height', () => { + expect(textarea.clientHeight).toEqual(textarea.scrollHeight); + + fixture.componentInstance.content = ` + Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat`; + autosize.triggerEventHandler('input', null); + fixture.detectChanges(); + expect(textarea.clientHeight).toEqual(textarea.scrollHeight); + }); + + it('the component should be identified by the directive', () => { + expect(autosize).toBeDefined(); + }); +}); diff --git a/packages/ngx-widgets/src/app/area-size/area-size.directive.ts b/packages/ngx-widgets/src/app/area-size/area-size.directive.ts new file mode 100644 index 000000000..25e402cef --- /dev/null +++ b/packages/ngx-widgets/src/app/area-size/area-size.directive.ts @@ -0,0 +1,25 @@ +import { Directive, ElementRef, HostListener, Renderer2, AfterViewInit } from '@angular/core'; + +@Directive({ + selector: '[textAreaResize]', +}) +export class AreaSizeDirective implements AfterViewInit { + private element: HTMLElement = this.elementRef.nativeElement; + + constructor(private elementRef: ElementRef, private renderer: Renderer2) {} + + ngAfterViewInit(): void { + this.renderer.setStyle( + this.element, + 'height', + `${this.elementRef.nativeElement.scrollHeight}px`, + ); + } + + @HostListener('input', ['$event']) + resizeOnInput(event: Event) { + const input = event.target as HTMLInputElement; + this.renderer.setStyle(this.element, 'height', '1px'); + this.renderer.setStyle(this.element, 'height', `${input.scrollHeight}px`); + } +} diff --git a/packages/ngx-widgets/src/app/area-size/area-size.module.ts b/packages/ngx-widgets/src/app/area-size/area-size.module.ts new file mode 100644 index 000000000..474b0dbea --- /dev/null +++ b/packages/ngx-widgets/src/app/area-size/area-size.module.ts @@ -0,0 +1,8 @@ +import { NgModule } from '@angular/core'; +import { AreaSizeDirective } from './area-size.directive'; + +@NgModule({ + declarations: [AreaSizeDirective], + exports: [AreaSizeDirective], +}) +export class AreaSizeModule {} diff --git a/packages/ngx-widgets/src/app/markdown/markdown.component.html b/packages/ngx-widgets/src/app/markdown/markdown.component.html index 11dc03f9e..2a539642f 100644 --- a/packages/ngx-widgets/src/app/markdown/markdown.component.html +++ b/packages/ngx-widgets/src/app/markdown/markdown.component.html @@ -17,15 +17,16 @@
-

+ [value]="rawText" + >
-1 && typeof this.inpRenderedText === 'undefined' ) { - console.warn('Markdown component change :: renderedText is passed undefined'); this.renderedText = ''; } else { this.renderedText = this.inpRenderedText; } if (Object.keys(changes).indexOf('inpRawText') > -1 && typeof this.inpRawText === 'undefined') { - console.warn('Markdown component change :: rawText is passed undefined'); this.rawText = ''; } else { this.rawText = this.inpRawText; @@ -135,11 +133,9 @@ export class MarkdownComponent implements OnChanges, OnInit, AfterViewChecked { ngOnInit() { if (typeof this.renderedText === 'undefined') { - console.warn('Markdown component init :: renderedText is passed undefined'); this.renderedText = ''; } if (typeof this.rawText === 'undefined') { - console.warn('Markdown component init :: rawText is passed undefined'); this.rawText = ''; } } @@ -158,11 +154,6 @@ export class MarkdownComponent implements OnChanges, OnInit, AfterViewChecked { } onInputEvent(event: any) { - console.log( - `In-Markup Markdown input Event detected for input type: ${ - event.type - } with extraData ${JSON.stringify(event.extraData)}`, - ); // we only support this interaction on checkboxes for now. // the mechanic is generic, add other controls below. In case, // you need to also add support for them in github-link-area as well. @@ -220,9 +211,9 @@ export class MarkdownComponent implements OnChanges, OnInit, AfterViewChecked { onClickPreviewTab() { if (this.viewType === 'markdown') { - if (this.rawText !== this.editorInput.nativeElement.innerText.trim()) { + if (this.rawText !== this.editorInput.nativeElement.value.trim()) { // Emit raw text to get preview - this.rawText = this.editorInput.nativeElement.innerText.trim(); + this.rawText = this.editorInput.nativeElement.value.trim(); this.showPreview.emit({ rawText: this.rawText, callBack: (t: string, m: string) => this.renderPreview(t, m), @@ -299,11 +290,11 @@ export class MarkdownComponent implements OnChanges, OnInit, AfterViewChecked { if (this.allowEmptySave || (!this.fieldEmpty && !this.allowEmptySave)) { if ( this.viewType === 'markdown' && - this.previousRawText !== this.editorInput.nativeElement.innerText.trim() + this.previousRawText !== this.editorInput.nativeElement.value.trim() ) { this.saving = true; this.onSaveClick.emit({ - rawText: this.editorInput.nativeElement.innerText.trim(), + rawText: this.editorInput.nativeElement.value.trim(), callBack: (t: string, m: string) => this.saveUpdate(t, m), }); } else if (this.viewType === 'preview' && this.previousRawText !== this.rawText) { @@ -335,13 +326,11 @@ export class MarkdownComponent implements OnChanges, OnInit, AfterViewChecked { renderPreview(rawText: string, renderedText: string) { this.rendering = false; if (typeof rawText === 'undefined') { - console.warn('Markdown component preview callback :: rawText is passed undefined'); this.rawText = ''; } else { this.rawText = rawText; } if (typeof renderedText === 'undefined') { - console.warn('Markdown component preview callback :: renderedText is passed undefined'); this.renderedText = ''; } else { this.renderedText = renderedText; @@ -352,13 +341,11 @@ export class MarkdownComponent implements OnChanges, OnInit, AfterViewChecked { saveUpdate(rawText: string, renderedText: any) { this.saving = false; if (typeof rawText === 'undefined') { - console.warn('Markdown component save callback :: rawText is passed undefined'); this.rawText = ''; } else { this.rawText = rawText; } if (typeof renderedText === 'undefined') { - console.warn('Markdown component save callback :: renderedText is passed undefined'); this.renderedText = ''; } else { this.renderedText = renderedText; diff --git a/packages/ngx-widgets/src/app/markdown/markdown.module.ts b/packages/ngx-widgets/src/app/markdown/markdown.module.ts index ad526feb3..3bb84241c 100644 --- a/packages/ngx-widgets/src/app/markdown/markdown.module.ts +++ b/packages/ngx-widgets/src/app/markdown/markdown.module.ts @@ -3,10 +3,11 @@ import { NgModule } from '@angular/core'; import { AlmEditableModule } from '../editable/almeditable.module'; import { GitHubLinkAreaModule } from '../github-link-area/github-link-area.module'; import { MarkdownComponent } from './markdown.component'; +import { AreaSizeModule } from '../area-size/area-size.module'; @NgModule({ declarations: [MarkdownComponent], - imports: [CommonModule, AlmEditableModule, GitHubLinkAreaModule], + imports: [CommonModule, AlmEditableModule, GitHubLinkAreaModule, AreaSizeModule], exports: [MarkdownComponent], }) export class MarkdownModule {}