Browse Source

add markdown and rich text editor as dependencies

pull/533/head
Ruud Faessen 6 years ago
parent
commit
0151ad36c1
  1. 215
      frontend/app/shared/components/forms/markdown-editor.component.ts
  2. 34
      frontend/app/shared/components/forms/rich-editor.component.ts
  3. 34
      frontend/package-lock.json
  4. 3
      frontend/package.json

215
frontend/app/shared/components/forms/markdown-editor.component.ts

@ -7,10 +7,11 @@
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, forwardRef, Renderer2, ViewChild } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ApiUrlConfig, AssetDto, AssetUploaderState, DialogModel, ResourceLoaderService, StatefulControlComponent, Types, UploadCanceled } from '@app/shared/internal';
import { ApiUrlConfig, AssetDto, AssetUploaderState, DialogModel, StatefulControlComponent, Types, UploadCanceled } from '@app/shared/internal';
import marked from 'marked';
declare var SimpleMDE: any;
import SimpleMDE from 'simplemde';
import 'simplemde/dist/simplemde.min.css';
export const SQX_MARKDOWN_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => MarkdownEditorComponent), multi: true
@ -49,8 +50,7 @@ export class MarkdownEditorComponent extends StatefulControlComponent<State, str
constructor(changeDetector: ChangeDetectorRef,
private readonly apiUrl: ApiUrlConfig,
private readonly assetUploader: AssetUploaderState,
private readonly renderer: Renderer2,
private readonly resourceLoader: ResourceLoaderService
private readonly renderer: Renderer2
) {
super(changeDetector, {
isFullscreen: false
@ -82,122 +82,119 @@ export class MarkdownEditorComponent extends StatefulControlComponent<State, str
}
public ngAfterViewInit() {
this.resourceLoader.loadStyle('https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css');
this.resourceLoader.loadScript('https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js').then(() => {
this.simplemde = new SimpleMDE({
previewRender: (text: string) => {
return marked(text, { pedantic: true });
this.simplemde = new SimpleMDE({
previewRender: (text: string) => {
return marked(text, { pedantic: true });
},
autoDownloadFontAwesome: true,
toolbar: [
{
name: 'bold',
action: SimpleMDE.toggleBold,
className: 'fa fa-bold',
title: 'Bold'
}, {
name: 'italic',
action: SimpleMDE.toggleItalic,
className: 'fa fa-italic',
title: 'Italic'
}, {
name: 'heading',
action: SimpleMDE.toggleHeadingSmaller,
className: 'fa fa-header',
title: 'Heading'
}, {
name: 'quote',
action: SimpleMDE.toggleBlockquote,
className: 'fa fa-quote-left',
title: 'Quote'
}, {
name: 'unordered-list',
action: SimpleMDE.toggleUnorderedList,
className: 'fa fa-list-ul',
title: 'Generic List'
}, {
name: 'ordered-list',
action: SimpleMDE.toggleOrderedList,
className: 'fa fa-list-ol',
title: 'Numbered List'
},
autoDownloadFontAwesome: true,
toolbar: [
{
name: 'bold',
action: SimpleMDE.toggleBold,
className: 'fa fa-bold',
title: 'Bold'
}, {
name: 'italic',
action: SimpleMDE.toggleItalic,
className: 'fa fa-italic',
title: 'Italic'
}, {
name: 'heading',
action: SimpleMDE.toggleHeadingSmaller,
className: 'fa fa-header',
title: 'Heading'
}, {
name: 'quote',
action: SimpleMDE.toggleBlockquote,
className: 'fa fa-quote-left',
title: 'Quote'
}, {
name: 'unordered-list',
action: SimpleMDE.toggleUnorderedList,
className: 'fa fa-list-ul',
title: 'Generic List'
}, {
name: 'ordered-list',
action: SimpleMDE.toggleOrderedList,
className: 'fa fa-list-ol',
title: 'Numbered List'
},
'|',
{
name: 'link',
action: SimpleMDE.drawLink,
className: 'fa fa-link',
title: 'Create Link'
}, {
name: 'image',
action: SimpleMDE.drawImage,
className: 'fa fa-picture-o',
title: 'Insert Image'
},
'|',
{
name: 'preview',
action: SimpleMDE.togglePreview,
className: 'fa fa-eye no-disable',
title: 'Toggle Preview'
}, {
name: 'fullscreen',
action: SimpleMDE.toggleFullScreen,
className: 'fa fa-arrows-alt no-disable no-mobile',
title: 'Toggle Fullscreen'
}, {
name: 'side-by-side',
action: SimpleMDE.toggleSideBySide,
className: 'fa fa-columns no-disable no-mobile',
title: 'Toggle Side by Side'
},
'|',
{
name: 'guide',
action: 'https://simplemde.com/markdown-guide',
className: 'fa fa-question-circle',
title: 'Markdown Guide'
},
'|',
{
name: 'assets',
action: this.showSelector,
className: 'icon-assets icon-bold',
title: 'Insert Assets'
}
],
element: this.editor.nativeElement
});
'|',
{
name: 'link',
action: SimpleMDE.drawLink,
className: 'fa fa-link',
title: 'Create Link'
}, {
name: 'image',
action: SimpleMDE.drawImage,
className: 'fa fa-picture-o',
title: 'Insert Image'
},
'|',
{
name: 'preview',
action: SimpleMDE.togglePreview,
className: 'fa fa-eye no-disable',
title: 'Toggle Preview'
}, {
name: 'fullscreen',
action: SimpleMDE.toggleFullScreen,
className: 'fa fa-arrows-alt no-disable no-mobile',
title: 'Toggle Fullscreen'
}, {
name: 'side-by-side',
action: SimpleMDE.toggleSideBySide,
className: 'fa fa-columns no-disable no-mobile',
title: 'Toggle Side by Side'
},
'|',
{
name: 'guide',
action: 'https://simplemde.com/markdown-guide',
className: 'fa fa-question-circle',
title: 'Markdown Guide'
},
'|',
{
name: 'assets',
action: this.showSelector,
className: 'icon-assets icon-bold',
title: 'Insert Assets'
}
],
element: this.editor.nativeElement
});
this.simplemde.value(this.value || '');
this.simplemde.codemirror.setOption('readOnly', this.isDisabled);
this.simplemde.value(this.value || '');
this.simplemde.codemirror.setOption('readOnly', this.isDisabled);
this.simplemde.codemirror.on('change', () => {
const value = this.simplemde.value();
this.simplemde.codemirror.on('change', () => {
const value = this.simplemde.value();
if (this.value !== value) {
this.value = value;
if (this.value !== value) {
this.value = value;
this.callChange(value);
}
});
this.callChange(value);
}
});
this.simplemde.codemirror.on('refresh', () => {
const isFullscreen = this.simplemde.isFullscreenActive();
this.simplemde.codemirror.on('refresh', () => {
const isFullscreen = this.simplemde.isFullscreenActive();
let target = this.container.nativeElement;
let target = this.container.nativeElement;
if (isFullscreen) {
target = document.body;
}
if (isFullscreen) {
target = document.body;
}
this.renderer.appendChild(target, this.inner.nativeElement);
this.renderer.appendChild(target, this.inner.nativeElement);
this.next(s => ({ ...s, isFullscreen }));
});
this.next(s => ({ ...s, isFullscreen }));
});
this.simplemde.codemirror.on('blur', () => {
this.callTouched();
});
this.simplemde.codemirror.on('blur', () => {
this.callTouched();
});
}

34
frontend/app/shared/components/forms/rich-editor.component.ts

@ -9,9 +9,19 @@
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, forwardRef, OnDestroy, Output, ViewChild } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ApiUrlConfig, AssetDto, AssetUploaderState, DialogModel, ResourceLoaderService, StatefulControlComponent, Types, UploadCanceled } from '@app/shared/internal';
import { ApiUrlConfig, AssetDto, AssetUploaderState, DialogModel, StatefulControlComponent, Types, UploadCanceled } from '@app/shared/internal';
declare var tinymce: any;
import tinymce from 'tinymce';
import 'tinymce/themes/silver';
import 'tinymce/plugins/advlist';
import 'tinymce/plugins/code';
import 'tinymce/plugins/image';
import 'tinymce/plugins/link';
import 'tinymce/plugins/lists';
import 'tinymce/plugins/media';
import 'tinymce/plugins/paste';
import 'tinymce/skins/ui/oxide/skin.min.css';
export const SQX_RICH_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => RichEditorComponent), multi: true
@ -48,8 +58,7 @@ export class RichEditorComponent extends StatefulControlComponent<undefined, str
constructor(changeDetector: ChangeDetectorRef,
private readonly apiUrl: ApiUrlConfig,
private readonly assetUploader: AssetUploaderState,
private readonly resourceLoader: ResourceLoaderService
private readonly assetUploader: AssetUploaderState
) {
super(changeDetector, undefined);
}
@ -62,17 +71,15 @@ export class RichEditorComponent extends StatefulControlComponent<undefined, str
}
public ngAfterViewInit() {
this.resourceLoader.loadScript('https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.2.0/tinymce.min.js').then(() => {
const timer = setInterval(() => {
const target = this.editor.nativeElement;
const timer = setInterval(() => {
const target = this.editor.nativeElement;
if (document.body.contains(target)) {
tinymce.init(this.getEditorOptions(target));
if (document.body.contains(target)) {
tinymce.init(this.getEditorOptions(target));
clearInterval(timer);
}
}, 10);
});
clearInterval(timer);
}
}, 10);
}
public reset() {
@ -96,7 +103,6 @@ export class RichEditorComponent extends StatefulControlComponent<undefined, str
return {
...DEFAULT_PROPS,
images_upload_handler: (blob: any, success: (url: string) => void, failure: (message: string) => void) => {
const file = new File([blob.blob()], blob.filename(), { lastModified: new Date().getTime() });

34
frontend/package-lock.json

@ -573,6 +573,12 @@
"@types/react": "*"
}
},
"@types/simplemde": {
"version": "1.11.7",
"resolved": "https://registry.npmjs.org/@types/simplemde/-/simplemde-1.11.7.tgz",
"integrity": "sha512-b3yirBar1gqb9clgJJKpx+Or3txkOOkm5sffhRKaBUfh7+1D2Aimx2RKXGS1LK9S5KyNmug3lwpGJtaID9cOnA==",
"dev": true
},
"@types/sizzle": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz",
@ -2300,6 +2306,14 @@
"graphql-language-service-parser": "^1.5.2"
}
},
"codemirror-spell-checker": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/codemirror-spell-checker/-/codemirror-spell-checker-1.1.2.tgz",
"integrity": "sha1-HGYPkIlIPMtRE7m6nKGcP0mTNx4=",
"requires": {
"typo-js": "*"
}
},
"collection-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@ -11181,6 +11195,16 @@
}
}
},
"simplemde": {
"version": "1.11.2",
"resolved": "https://registry.npmjs.org/simplemde/-/simplemde-1.11.2.tgz",
"integrity": "sha1-ojo12XjSxA7wfewAjJLwcNjggOM=",
"requires": {
"codemirror": "*",
"codemirror-spell-checker": "*",
"marked": "*"
}
},
"slice-ansi": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz",
@ -12293,6 +12317,11 @@
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
"dev": true
},
"tinymce": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/tinymce/-/tinymce-5.2.0.tgz",
"integrity": "sha512-Q7KAu9sLB6TBhKFdb2LHPGy770zkSEjpN1VRqZ6pxNuVQ0mbGWgMocHDvM9XL9yJaOhFrJP6s9XM7zG2gapGpA=="
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@ -12627,6 +12656,11 @@
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
"dev": true
},
"typo-js": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.1.0.tgz",
"integrity": "sha512-W3kLbx+ML9PBl5Bzso/lTvVxk4BCveSNAtQeht59FEtxCdGThmn6wSHA4Xq3eQYAK24NHdisMM4JmsK0GFy/pg=="
},
"uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",

3
frontend/package.json

@ -45,7 +45,9 @@
"react": "16.10.2",
"react-dom": "16.10.2",
"rxjs": "6.5.4",
"simplemde": "^1.11.2",
"slugify": "1.4.0",
"tinymce": "^5.2.0",
"tslib": "1.11.1",
"zone.js": "0.10.3"
},
@ -62,6 +64,7 @@
"@types/node": "13.7.4",
"@types/react": "16.9.21",
"@types/react-dom": "16.9.5",
"@types/simplemde": "^1.11.2",
"@types/tinymce": "4.5.24",
"browserslist": "4.9.1",
"caniuse-lite": "1.0.30001055",

Loading…
Cancel
Save