Browse Source

Styling fixes and markdown support for errors and notifications.

release/3.x
Sebastian 6 years ago
parent
commit
7e880aee10
  1. 4
      src/Squidex/app/features/content/pages/content/content-page.component.ts
  2. 2
      src/Squidex/app/framework/angular/forms/form-error.component.ts
  3. 4
      src/Squidex/app/framework/angular/modals/dialog-renderer.component.html
  4. 30
      src/Squidex/app/framework/angular/pipes/markdown.pipe.spec.ts
  5. 29
      src/Squidex/app/framework/angular/pipes/markdown.pipe.ts
  6. 1
      src/Squidex/app/framework/declarations.ts
  7. 3
      src/Squidex/app/framework/module.ts
  8. 4
      src/Squidex/app/framework/utils/error.spec.ts
  9. 40
      src/Squidex/app/framework/utils/error.ts
  10. 36
      src/Squidex/app/shared/components/help-markdown.pipe.spec.ts
  11. 6
      src/Squidex/app/shared/components/help-markdown.pipe.ts
  12. 6
      src/Squidex/app/theme/_forms.scss

4
src/Squidex/app/features/content/pages/content/content-page.component.ts

@ -156,7 +156,7 @@ export class ContentPageComponent extends ResourceOwner implements CanComponentD
}
public canDeactivate(): Observable<boolean> {
return this.checkPendingChanges('close current content view').pipe(
return this.checkPendingChanges('close the current content view').pipe(
tap(confirmed => {
if (confirmed) {
this.autoSaveService.remove(this.autoSaveKey);
@ -267,7 +267,7 @@ export class ContentPageComponent extends ResourceOwner implements CanComponentD
private checkPendingChanges(action: string) {
return this.contentForm.hasChanged() ?
this.dialogs.confirm('Unsaved changes', `You have unsaved changes. When you ${action} you will loose them.<br />Do you want to continue anyway?`) :
this.dialogs.confirm('Unsaved changes', `You have unsaved changes.\n\nWhen you ${action} you will loose them.\n\n*Do you want to continue anyway?*`) :
of(true);
}

2
src/Squidex/app/framework/angular/forms/form-error.component.ts

@ -18,7 +18,7 @@ import { ErrorDto } from '@app/framework/internal';
<a class="form-alert-close" (click)="close()">
<i class="icon-close"></i>
</a>
<div [innerHTML]="error?.displayMessage"></div>
<div [innerHTML]="error?.displayMessage | sqxMarkdown"></div>
</div>
</div>
</ng-container>`,

4
src/Squidex/app/framework/angular/modals/dialog-renderer.component.html

@ -7,7 +7,7 @@
</ng-container>
<ng-container content>
<span [innerHTML]="snapshot.dialogRequest?.text"></span>
<span [innerHTML]="snapshot.dialogRequest?.text | sqxMarkdown"></span>
</ng-container>
<ng-container footer>
@ -21,7 +21,7 @@
<div class="alert alert-dismissible alert-{{notification.messageType}}" *ngFor="let notification of snapshot.notifications" (click)="close(notification)" @fade>
<button type="button" class="close" data-dismiss="alert" (close)="close(notification)">&times;</button>
<span [innerHTML]="notification.message"></span>
<span [innerHTML]="notification.message | sqxMarkdown"></span>
</div>
</div>

30
src/Squidex/app/framework/angular/pipes/markdown.pipe.spec.ts

@ -0,0 +1,30 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { MarkdownPipe } from './markdown.pipe';
describe('MarkdownPipe', () => {
it('should convert link to html', () => {
const actual = new MarkdownPipe().transform('[link-name](link-url)');
expect(actual).toBe('<p><a href="link-url" target="_blank", rel="noopener">link-name <i class="icon-external-link"></i></a></p>\n');
});
it('should convert markdown to html', () => {
const actual = new MarkdownPipe().transform('*bold*');
expect(actual).toBe('<p><em>bold</em></p>\n');
});
[null, undefined, ''].map(x => {
it('should return empty string for invalid value', () => {
const actual = new MarkdownPipe().transform(x);
expect(actual).toBe('');
});
});
});

29
src/Squidex/app/framework/angular/pipes/markdown.pipe.ts

@ -0,0 +1,29 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Pipe, PipeTransform } from '@angular/core';
import Marked from 'marked';
const renderer = new Marked.Renderer();
renderer.link = (href, _, text) => {
return `<a href="${href}" target="_blank", rel="noopener">${text} <i class="icon-external-link"></i></a>`;
};
@Pipe({
name: 'sqxMarkdown',
pure: true
})
export class MarkdownPipe implements PipeTransform {
public transform(text: string | null | undefined): string {
if (text) {
return Marked(text, { renderer });
} else {
return '';
}
}
}

1
src/Squidex/app/framework/declarations.ts

@ -46,6 +46,7 @@ export * from './angular/modals/tooltip.directive';
export * from './angular/pipes/colors.pipes';
export * from './angular/pipes/date-time.pipes';
export * from './angular/pipes/keys.pipe';
export * from './angular/pipes/markdown.pipe';
export * from './angular/pipes/money.pipe';
export * from './angular/pipes/name.pipe';
export * from './angular/pipes/numbers.pipes';

3
src/Squidex/app/framework/module.ts

@ -59,6 +59,7 @@ import {
LoadingInterceptor,
LoadingService,
LocalStoreService,
MarkdownPipe,
MessageBus,
ModalDialogComponent,
ModalDirective,
@ -142,6 +143,7 @@ import {
KeysPipe,
KNumberPipe,
LightenPipe,
MarkdownPipe,
ModalDialogComponent,
ModalDirective,
ModalPlacementDirective,
@ -214,6 +216,7 @@ import {
KeysPipe,
KNumberPipe,
LightenPipe,
MarkdownPipe,
ModalDirective,
ModalDialogComponent,
ModalPlacementDirective,

4
src/Squidex/app/framework/utils/error.spec.ts

@ -29,12 +29,12 @@ describe('ErrorDto', () => {
it('Should create append do to simple message when detail has one item', () => {
const error = new ErrorDto(500, 'Error Message', ['Detail Message']);
expect(error.displayMessage).toBe('Error Message: Detail Message.');
expect(error.displayMessage).toBe('Error Message.\n\n * Detail Message.\n');
});
it('Should create html list when error has more items.', () => {
const error = new ErrorDto(500, 'Error Message', ['Detail1.', 'Detail2.']);
expect(error.displayMessage).toBe('Error Message.<ul><li>Detail1.</li><li>Detail2.</li></ul>');
expect(error.displayMessage).toBe('Error Message.\n\n * Detail1.\n * Detail2.\n');
});
});

40
src/Squidex/app/framework/utils/error.ts

@ -23,39 +23,25 @@ export class ErrorDto {
}
function formatMessage(message: string, details?: ReadonlyArray<string>) {
const appendLast = (row: string, char: string) => {
const last = row[row.length - 1];
let result = appendLast(message, '.');
if (last !== char) {
return row + char;
} else {
return row;
}
};
const removeLast = (row: string, char: string) => {
const last = row[row.length - 1];
if (last === char) {
return row.substr(0, row.length - 1);
} else {
return row;
}
};
if (details && details.length > 1) {
let result = appendLast(message, '.') + '<ul>';
if (details && details.length > 0) {
result += '\n\n';
for (const detail of details) {
result += `<li>${appendLast(detail, '.')}</li>`;
result += ` * ${appendLast(detail, '.')}\n`;
}
}
return result;
}
result = result + '</ul>';
function appendLast(row: string, char: string) {
const last = row[row.length - 1];
return result;
} else if (details && details.length === 1) {
return `${appendLast(removeLast(message, '.'), ':')} ${appendLast(details[0], '.')}`;
if (last !== char) {
return row + char;
} else {
return appendLast(message, '.');
return row;
}
}

36
src/Squidex/app/shared/components/help-markdown.pipe.spec.ts

@ -0,0 +1,36 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { HelpMarkdownPipe } from './help-markdown.pipe';
describe('MarkdownPipe', () => {
it('should convert absolute link to html', () => {
const actual = new HelpMarkdownPipe().transform('[link-name](https://squidex.io)');
expect(actual).toBe('<p><a href="https://squidex.io" target="_blank", rel="noopener">link-name <i class="icon-external-link"></i></a></p>\n');
});
it('should convert relative link to html', () => {
const actual = new HelpMarkdownPipe().transform('[link-name](link-url)');
expect(actual).toBe('<p><a href="https://docs.squidex.io/link-url" target="_blank", rel="noopener">link-name <i class="icon-external-link"></i></a></p>\n');
});
it('should convert markdown to html', () => {
const actual = new HelpMarkdownPipe().transform('*bold*');
expect(actual).toBe('<p><em>bold</em></p>\n');
});
[null, undefined, ''].map(x => {
it('should return empty string for invalid value', () => {
const actual = new HelpMarkdownPipe().transform(x);
expect(actual).toBe('');
});
});
});

6
src/Squidex/app/shared/components/help-markdown.pipe.ts

@ -10,12 +10,12 @@ import * as Marked from 'marked';
const renderer = new Marked.Renderer();
renderer.link = (href, title, text) => {
renderer.link = (href, _, text) => {
if (!href.startsWith('http')) {
href = `https://docs.squidex.io/${href}`;
}
return `<a href="${href}" title="${title}" target="_blank", rel="noopener">${text} <i class="icon-external-link"></i></a>`;
return `<a href="${href}" target="_blank", rel="noopener">${text} <i class="icon-external-link"></i></a>`;
};
@Pipe({
@ -23,7 +23,7 @@ renderer.link = (href, title, text) => {
pure: true
})
export class HelpMarkdownPipe implements PipeTransform {
public transform(text: string | null): string {
public transform(text: string | null | undefined): string {
if (text) {
return Marked(text, { renderer });
} else {

6
src/Squidex/app/theme/_forms.scss

@ -116,11 +116,11 @@
@include absolute(.25rem, 0, auto, auto);
padding: 1rem;
min-width: 200px;
max-width: 400px;
max-width: 600px;
font-size: 1rem;
font-weight: normal;
text-align: left;
z-index: 1000;
z-index: 2000;
&::after {
@include absolute(-.75rem, .625rem, auto, auto);
@ -184,7 +184,7 @@
label {
& {
color: black;
color: $color-title;
}
.hint {

Loading…
Cancel
Save