Headless CMS and Content Managment Hub
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

211 lines
6.9 KiB

/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, forwardRef, Renderer2, ViewChild } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import {
AssetDto,
DialogModel,
ResourceLoaderService,
StatefulControlComponent,
Types
} from '@app/shared/internal';
declare var SimpleMDE: any;
export const SQX_MARKDOWN_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => MarkdownEditorComponent), multi: true
};
interface State {
isFullscreen: false;
}
@Component({
selector: 'sqx-markdown-editor',
styleUrls: ['./markdown-editor.component.scss'],
templateUrl: './markdown-editor.component.html',
providers: [SQX_MARKDOWN_EDITOR_CONTROL_VALUE_ACCESSOR],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MarkdownEditorComponent extends StatefulControlComponent<State, string> implements AfterViewInit {
private simplemde: any;
private value: string;
private isDisabled = false;
public assetsDialog = new DialogModel();
@ViewChild('editor')
public editor: ElementRef;
@ViewChild('container')
public container: ElementRef;
@ViewChild('inner')
public inner: ElementRef;
constructor(changeDetector: ChangeDetectorRef,
private readonly renderer: Renderer2,
private readonly resourceLoader: ResourceLoaderService
) {
super(changeDetector, {
isFullscreen: false
});
this.resourceLoader.loadStyle('https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css');
}
public writeValue(obj: any) {
this.value = Types.isString(obj) ? obj : '';
if (this.simplemde) {
this.simplemde.value(this.value);
}
}
public setDisabledState(isDisabled: boolean): void {
this.isDisabled = isDisabled;
if (this.simplemde) {
this.simplemde.codemirror.setOption('readOnly', isDisabled);
}
}
private showSelector = () => {
this.assetsDialog.show();
}
public ngAfterViewInit() {
this.resourceLoader.loadScript('https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js').then(() => {
this.simplemde = new SimpleMDE({
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
});
this.simplemde.value(this.value || '');
this.simplemde.codemirror.setOption('readOnly', this.isDisabled);
this.simplemde.codemirror.on('change', () => {
const value = this.simplemde.value();
if (this.value !== value) {
this.value = value;
this.callChange(value);
}
});
this.simplemde.codemirror.on('refresh', () => {
const isFullscreen = this.simplemde.isFullscreenActive();
let target = this.container.nativeElement;
if (isFullscreen) {
target = document.body;
}
this.renderer.appendChild(target, this.inner.nativeElement);
this.next(s => ({ ...s, isFullscreen }));
});
this.simplemde.codemirror.on('blur', () => {
this.callTouched();
});
});
}
public insertAssets(assets: AssetDto[]) {
let content = '';
for (let asset of assets) {
content += `![${asset.fileName}](${asset.url} '${asset.fileName}')`;
}
if (content.length > 0) {
this.simplemde.codemirror.replaceSelection(content);
}
this.assetsDialog.hide();
}
}