src/app/drafts/draft-edit/draft-edit.component.html
<form
[formGroup]="form"
class="article-editor"
>
<div class="article-editor__title">
<input
type="text"
id="register-article-title"
formControlName="title"
placeholder="タイトル" />
<div
*ngIf="messageService.hasError(title, 'required') || messageService.hasError(title, 'maxlength') || messageService.hasErrorWithoutDirty(title, 'remote')"
class="register-article-title__messages">
<mat-error *ngIf="messageService.hasError(title, 'required')">
{{ messageService.get('required',['タイトル']) }}
</mat-error>
<mat-error *ngIf="messageService.hasError(title, 'maxlength')">
{{ messageService.get('maxlength',['タイトル' , title.getError('maxlength').requiredLength]) }}
</mat-error>
<mat-error *ngIf="messageService.hasErrorWithoutDirty(title, 'remote')">
<ng-container *ngFor="let msg of title.getError('remote')">
{{msg}}<br>
</ng-container>
</mat-error>
</div>
</div>
<div class="article-editor__format-operation">
<mat-checkbox
formControlName="isMarkdown"
>Markdonw形式</mat-checkbox>
<div
*ngIf="isMarkdown.value"
class="editor-support">
<i
matTooltip="太字"
matTooltipPosition="above"
[matTooltipShowDelay]="Constant.TOOL_TIP_SHOW_DELAY"
(click)='draftEditAreaComponent.insertContentToCaretPosition("**", "**")'
class="fa fa-fw fa-bold editor-support__icon"
></i>
<i
matTooltip="斜線"
matTooltipPosition="above"
[matTooltipShowDelay]="Constant.TOOL_TIP_SHOW_DELAY"
(click)='draftEditAreaComponent.insertContentToCaretPosition("_", "_")'
class="fa fa-fw fa-italic editor-support__icon"
></i>
<i
matTooltip="取り消し線"
matTooltipPosition="above"
[matTooltipShowDelay]="Constant.TOOL_TIP_SHOW_DELAY"
(click)='draftEditAreaComponent.insertContentToCaretPosition("~~", "~~")'
class="fa fa-fw fa-strikethrough editor-support__icon"
></i>
<i class="editor-support__separator"></i>
<i
matTooltip="ヘッダー"
matTooltipPosition="above"
[matTooltipShowDelay]="Constant.TOOL_TIP_SHOW_DELAY"
[matMenuTriggerFor]="menu"
class="fa fa-fw fa-header editor-support__icon"
></i>
<mat-menu
#menu="matMenu"
[overlapTrigger]="false"
yPosition="below"
class="header-menu">
<button
mat-menu-item
(click)='draftEditAreaComponent.insertToLineStart("# ")'
>
<span class="header-menu__h1"> H1: Header</span>
</button>
<button
mat-menu-item
(click)='draftEditAreaComponent.insertToLineStart("## ")'
>
<span class="header-menu__h2"> H2: Header</span>
</button>
<button
mat-menu-item
(click)='draftEditAreaComponent.insertToLineStart("### ")'
>
<span class="header-menu__h3"> H3: Header</span>
</button>
<button
mat-menu-item
(click)='draftEditAreaComponent.insertToLineStart("#### ")'
>
<span class="header-menu__h4"> H4: Header</span>
</button>
<button
mat-menu-item
(click)='draftEditAreaComponent.insertToLineStart("##### ")'
>
<span class="header-menu__h5"> H5: Header</span>
</button>
<button
mat-menu-item
(click)='draftEditAreaComponent.insertToLineStart("###### ")'
>
<span class="header-menu__h6"> H6: Header</span>
</button>
</mat-menu>
<i
matTooltip="リンク"
matTooltipPosition="above"
[matTooltipShowDelay]="Constant.TOOL_TIP_SHOW_DELAY"
(click)='draftEditAreaComponent.insertContentToCaretPosition("[", "](https://)")'
class="fa fa-fw fa-link editor-support__icon"
></i>
<i
matTooltip="ソースコード"
matTooltipPosition="above"
[matTooltipShowDelay]="Constant.TOOL_TIP_SHOW_DELAY"
(click)="draftEditAreaComponent.insertCodeWrapper()"
class="fa fa-fw fa-code editor-support__icon"
></i>
<i
matTooltip="引用"
matTooltipPosition="above"
[matTooltipShowDelay]="Constant.TOOL_TIP_SHOW_DELAY"
(click)='draftEditAreaComponent.insertToLineStart("> ")'
class="fa fa-fw fa-quote-left editor-support__icon"
></i>
<i
matTooltip="水平線"
matTooltipPosition="above"
[matTooltipShowDelay]="Constant.TOOL_TIP_SHOW_DELAY"
(click)='draftEditAreaComponent.insertContentToCaretPosition("", "\n\n---\n")'
class="fa fa-fw fa-minus editor-support__icon"
></i>
<i class="editor-support__separator"></i>
<i
matTooltip="リスト"
matTooltipPosition="above"
[matTooltipShowDelay]="Constant.TOOL_TIP_SHOW_DELAY"
(click)='draftEditAreaComponent.insertToLineStart("* ")'
class="fa fa-fw fa-list-ul editor-support__icon"
></i>
<i
matTooltip="順序付きリスト"
matTooltipPosition="above"
[matTooltipShowDelay]="Constant.TOOL_TIP_SHOW_DELAY"
(click)='draftEditAreaComponent.insertToLineStart("1. ")'
class="fa fa-fw fa-list-ol editor-support__icon"
></i>
<i
matTooltip="テーブル"
matTooltipPosition="above"
[matTooltipShowDelay]="Constant.TOOL_TIP_SHOW_DELAY"
(click)='draftEditAreaComponent.insertContentToCaretPosition("", "\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n")'
class="fa fa-fw fa-table editor-support__icon"
></i>
</div>
<mat-button-toggle-group
*ngIf="isMarkdown.value"
[(ngModel)]="markdonwEditMode"
[ngModelOptions]="{standalone: true}"
class="select-format article-editor__select-format">
<mat-button-toggle
[value]="MarkdownEditMode[MarkdownEditMode.notPreviewing]"
matTooltip="エディターのみ表示"
[matTooltipShowDelay]="Constant.TOOL_TIP_SHOW_DELAY"
class="select-format__button"
>
<i class="fa fa-fw fa-pencil-square-o" aria-hidden="true"></i>
</mat-button-toggle>
<mat-button-toggle
[value]="MarkdownEditMode[MarkdownEditMode.harfPreviewing]"
matTooltip="両方を表示"
[matTooltipShowDelay]="Constant.TOOL_TIP_SHOW_DELAY"
class="select-format__button_icon_twice">
<i class="fa fa-fw fa-pencil-square-o" aria-hidden="true"></i> | <i class="fa fa-fw fa-eye" aria-hidden="true"></i>
</mat-button-toggle>
<mat-button-toggle
[value]="MarkdownEditMode[MarkdownEditMode.fullPreviewing]"
matTooltip="プレビューのみ表示"
[matTooltipShowDelay]="Constant.TOOL_TIP_SHOW_DELAY"
class="select-format__button">
<i class="fa fa-fw fa-eye" aria-hidden="true"></i>
</mat-button-toggle>
</mat-button-toggle-group>
</div>
<div *ngIf="isMarkdown.value; then bodyMarkdown else bodyPlainText"></div>
<ng-template #bodyMarkdown>
<div class="article-editor__main markdonw-editor" >
<div
appDragAndDrop
(filesChangeEmiter)="onFilesChange($event)"
[allowed_extensions]="['png', 'jpg', 'bmp']"
[ngClass]="['markdonw-editor__row-text', markdonwEditMode]">
<app-draft-edit-area
[body]="body"
(scroll)="onScroll($event)"
></app-draft-edit-area>
</div>
<div class="image-operation" [class.show]="isImageOperationShow">
<div class="image-operation__header">
<button
*ngIf="imageForDisplayList?.length > 0"
mat-icon-button
class="image-operation__header__showhide-btn"
(click)="isImageOperationShow = !isImageOperationShow"
>
<i
class="fa fa-fw"
[class.fa-chevron-up]="!isImageOperationShow"
[class.fa-chevron-down]="isImageOperationShow"
></i>
</button>
<div
matRipple
class="image-operation__header__showhide-btn"
(click)="imageFile.click()">画像アップロード</div>
<input
hidden
type="file"
(change)="onFilesChange($event.srcElement.files)" #imageFile>
</div>
<div>
<ng-container
*ngIf="isImageOperationShow"
>
<div
class="image-operation__image"
*ngFor="let imageForDisplay of imageForDisplayList">
<button
mat-icon-button
class="image-operation__image__insert-btn"
(click)="draftEditAreaComponent.insertImageToArticle(imageForDisplay)"
><i class="fa fa-fw fa-plus-square"></i></button>
<div class="image-operation__image__file-name">{{imageForDisplay.fileName}}</div>
<div class="image-operation__image__spacer"></div>
<button
mat-icon-button
class="image-operation__image__delete-btn"
(click)="deleteImage(imageForDisplay)"
><i class="fa fa-fw fa-trash"></i></button>
</div>
</ng-container>
</div>
</div>
<div [ngClass]="['markdonw-editor__preview', markdonwEditMode]" #syncScrollTarget>
<p [innerHTML]="(body.value | toMarkdown).text" class="markdown-body"></p>
</div>
</div>
</ng-template>
<ng-template #bodyPlainText>
<div class="article-editor__main plain-text-editor">
<div class="plain-text-editor__row-text">
<textarea
id="register-article-body"
formControlName="body"
placeholder="本文"></textarea>
</div>
</div>
</ng-template>
<div class="article-editor__operation">
<button
mat-raised-button
type="button"
id="cancel-btn"
(click)='cancel(form.dirty)'><i class="fa fa-times"></i> キャンセル</button>
<div class="spacer"></div>
<div
*ngIf="messageService.hasError(body, 'required') || messageService.hasError(body, 'maxlength') || messageService.hasErrorWithoutDirty(body, 'remote')"
class="register-article-body__messages">
<mat-error *ngIf="messageService.hasError(body, 'required')">
{{ messageService.get('required',['本文']) }}
</mat-error>
<mat-error *ngIf="messageService.hasError(body, 'maxlength')">
{{ messageService.get('maxlength',['本文' , body.getError('maxlength').requiredLength]) }}
</mat-error>
<mat-error *ngIf="messageService.hasErrorWithoutDirty(body, 'remote')">
<ng-container *ngFor="let msg of body.getError('remote')">
{{msg}}<br>
</ng-container>
</mat-error>
</div>
<button
*ngIf="!canRegisterDraft"
mat-raised-button
color="accent"
type="button"
disabled
><i class="fa fa-floppy-o"></i> 下書きは{{Constant.MAX_DRAFT_COUNT}}件以上保存できません</button>
<button
*ngIf="canRegisterDraft"
mat-raised-button
color="accent"
type="button"
[disabled]="!form.valid"
id="registe-draft-btn"
(click)="upsertDraft(form)"
><i class="fa fa-floppy-o"></i> 下書き保存</button>
<button
mat-raised-button
color="primary"
type="submit"
[disabled]="!form.valid"
(click)="upsertArticle(form)"
id="registe-article-btn"><i class="fa fa-upload"></i> {{action}}</button>
</div>
</form>