Skip to content
This repository has been archived by the owner on May 7, 2021. It is now read-only.

Commit

Permalink
fix(preview): Markdown component layout breaks on copy-paste (#3510)
Browse files Browse the repository at this point in the history
- Made textaret instead of a contenteditable element
  • Loading branch information
Bumbilo authored and christianvogt committed Feb 8, 2019
1 parent 34e3bbd commit 18429cb
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 21 deletions.
47 changes: 47 additions & 0 deletions 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: '<textarea textAreaResize class="editor-box editor-markdown">{{content}}</textarea>',
})
class TestComponent {
content: string = '';
}

describe('area-size directive: ', () => {
let component: TestComponent;
let fixture: ComponentFixture<TestComponent>;
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();
});
});
25 changes: 25 additions & 0 deletions 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`);
}
}
8 changes: 8 additions & 0 deletions 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 {}
7 changes: 4 additions & 3 deletions packages/ngx-widgets/src/app/markdown/markdown.component.html
Expand Up @@ -17,15 +17,16 @@
<div class="editor-icon-container">
<i *ngIf="editAllow" (click)="activeEditor()" class="pficon-edit edit-icon"></i>
</div>
<p
<textarea
almEditable
textAreaResize
#editorInput
*ngIf="viewType === 'markdown'"
[editable]="true"
class="editor-box editor-markdown"
(keyup)="editorKeyUp($event)"
[innerText]="rawText"
></p>
[value]="rawText"
></textarea>
<div
#editorBox
#previewArea
Expand Down
11 changes: 11 additions & 0 deletions packages/ngx-widgets/src/app/markdown/markdown.component.less
Expand Up @@ -35,6 +35,15 @@
tr:nth-child(even) {
background-color: @color-pf-black-150;
}
ul {
display: block;
list-style-type: disc;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0px;
margin-inline-end: 0px;
padding-inline-start: 40px;
}
}
.placeholder {
font-size: 1em;
Expand All @@ -48,6 +57,8 @@
padding-right: 30px;
padding-bottom: 10px;
padding-left: 10px;
border: none;
resize: none;
}
.editor-icon-container {
position: relative;
Expand Down
21 changes: 4 additions & 17 deletions packages/ngx-widgets/src/app/markdown/markdown.component.ts
Expand Up @@ -120,13 +120,11 @@ export class MarkdownComponent implements OnChanges, OnInit, AfterViewChecked {
Object.keys(changes).indexOf('inpRenderedText') > -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;
Expand All @@ -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 = '';
}
}
Expand All @@ -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.
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion packages/ngx-widgets/src/app/markdown/markdown.module.ts
Expand Up @@ -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 {}

0 comments on commit 18429cb

Please sign in to comment.