Browse Source

Help UI improvements

pull/5451/head
Igor Kulikov 5 years ago
parent
commit
0e279c50f6
  1. 7
      ui-ngx/src/app/shared/components/help-popup.component.ts
  2. 70
      ui-ngx/src/app/shared/components/marked-options.service.ts
  3. 3
      ui-ngx/src/styles.scss

7
ui-ngx/src/app/shared/components/help-popup.component.ts

@ -31,7 +31,7 @@ import { isDefinedAndNotNull } from '@core/utils';
@Component({ @Component({
// tslint:disable-next-line:component-selector // tslint:disable-next-line:component-selector
selector: '[tb-help-popup]', selector: '[tb-help-popup], [tb-help-popup-content]',
templateUrl: './help-popup.component.html', templateUrl: './help-popup.component.html',
styleUrls: ['./help-popup.component.scss'], styleUrls: ['./help-popup.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
@ -44,6 +44,9 @@ export class HelpPopupComponent implements OnChanges, OnDestroy {
// tslint:disable-next-line:no-input-rename // tslint:disable-next-line:no-input-rename
@Input('tb-help-popup') helpId: string; @Input('tb-help-popup') helpId: string;
// tslint:disable-next-line:no-input-rename
@Input('tb-help-popup-content') helpContent: string;
// tslint:disable-next-line:no-input-rename // tslint:disable-next-line:no-input-rename
@Input('trigger-text') triggerText: string; @Input('trigger-text') triggerText: string;
@ -82,7 +85,7 @@ export class HelpPopupComponent implements OnChanges, OnDestroy {
const trigger = this.textMode ? this.toggleHelpTextButton.nativeElement : this.toggleHelpButton.nativeElement; const trigger = this.textMode ? this.toggleHelpTextButton.nativeElement : this.toggleHelpButton.nativeElement;
this.popoverService.toggleHelpPopover(trigger, this.renderer, this.viewContainerRef, this.popoverService.toggleHelpPopover(trigger, this.renderer, this.viewContainerRef,
this.helpId, this.helpId,
'', this.helpContent,
(visible) => { (visible) => {
this.popoverVisible = visible; this.popoverVisible = visible;
}, (ready => { }, (ready => {

70
ui-ngx/src/app/shared/components/marked-options.service.ts

@ -23,6 +23,7 @@ import { Tokenizer } from 'marked';
import * as marked from 'marked'; import * as marked from 'marked';
const copyCodeBlock = '{:copy-code}'; const copyCodeBlock = '{:copy-code}';
const codeStyleRegex = '^{:code-style="(.*)"}\n';
const autoBlock = '{:auto}'; const autoBlock = '{:auto}';
const targetBlankBlock = '{:target="_blank"}'; const targetBlankBlock = '{:target="_blank"}';
@ -70,13 +71,13 @@ export class MarkedOptionsService extends MarkedOptions {
}; };
marked.use({tokenizer}); marked.use({tokenizer});
this.renderer.code = (code: string, language: string | undefined, isEscaped: boolean) => { this.renderer.code = (code: string, language: string | undefined, isEscaped: boolean) => {
if (code.endsWith(copyCodeBlock)) { const codeContext = processCode(code);
code = code.substring(0, code.length - copyCodeBlock.length); if (codeContext.copyCode) {
const content = postProcessCodeContent(this.renderer2.code(code, language, isEscaped), code); const content = postProcessCodeContent(this.renderer2.code(codeContext.code, language, isEscaped), codeContext);
this.id++; this.id++;
return this.wrapCopyCode(this.id, content, code); return this.wrapCopyCode(this.id, content, codeContext);
} else { } else {
return this.wrapDiv(postProcessCodeContent(this.renderer2.code(code, language, isEscaped), code)); return this.wrapDiv(postProcessCodeContent(this.renderer2.code(codeContext.code, language, isEscaped), codeContext));
} }
}; };
this.renderer.table = (header: string, body: string) => { this.renderer.table = (header: string, body: string) => {
@ -95,10 +96,11 @@ export class MarkedOptionsService extends MarkedOptions {
header: boolean; header: boolean;
align: 'center' | 'left' | 'right' | null; align: 'center' | 'left' | 'right' | null;
}) => { }) => {
if (content.endsWith(copyCodeBlock)) { const codeContext = processCode(content);
content = content.substring(0, content.length - copyCodeBlock.length); codeContext.multiline = false;
if (codeContext.copyCode) {
this.id++; this.id++;
content = this.wrapCopyCode(this.id, content, content); content = this.wrapCopyCode(this.id, codeContext.code, codeContext);
} }
return this.renderer2.tablecell(content, flags); return this.renderer2.tablecell(content, flags);
}; };
@ -119,10 +121,14 @@ export class MarkedOptionsService extends MarkedOptions {
return `<div>${content}</div>`; return `<div>${content}</div>`;
} }
private wrapCopyCode(id: number, content: string, code: string): string { private wrapCopyCode(id: number, content: string, context: CodeContext): string {
let copyCodeButtonClass = 'clipboard-btn';
if (context.multiline) {
copyCodeButtonClass += ' multiline';
}
return `<div class="code-wrapper noChars" id="codeWrapper${id}" onClick="markdownCopyCode(${id})">${content}` + return `<div class="code-wrapper noChars" id="codeWrapper${id}" onClick="markdownCopyCode(${id})">${content}` +
`<span id="copyCodeId${id}" style="display: none;">${encodeURIComponent(code)}</span>` + `<span id="copyCodeId${id}" style="display: none;">${encodeURIComponent(context.code)}</span>` +
`<button class="clipboard-btn">\n` + `<button class="${copyCodeButtonClass}">\n` +
` <p>${this.translate.instant('markdown.copy-code')}</p>\n` + ` <p>${this.translate.instant('markdown.copy-code')}</p>\n` +
` <div>\n` + ` <div>\n` +
` <img src="/assets/copy-code-icon.svg" alt="${this.translate.instant('markdown.copy-code')}">\n` + ` <img src="/assets/copy-code-icon.svg" alt="${this.translate.instant('markdown.copy-code')}">\n` +
@ -187,13 +193,41 @@ export class MarkedOptionsService extends MarkedOptions {
} }
} }
function postProcessCodeContent(content: string, code: string): string { interface CodeContext {
const lineCount = code.trim().split('\n').length; copyCode: boolean;
let replacement; multiline: boolean;
if (lineCount < 2) { codeStyle?: string;
replacement = '<pre ngNonBindable class="no-line-numbers">'; code: string;
} else { }
replacement = '<pre ngNonBindable>';
function processCode(code: string): CodeContext {
const context: CodeContext = {
copyCode: false,
multiline: false,
code
};
if (context.code.endsWith(copyCodeBlock)) {
context.code = context.code.substring(0, context.code.length - copyCodeBlock.length);
context.copyCode = true;
}
const codeStyleMatch = context.code.match(new RegExp(codeStyleRegex));
if (codeStyleMatch) {
context.codeStyle = codeStyleMatch[1];
context.code = context.code.replace(new RegExp(codeStyleRegex), '');
}
const lineCount = context.code.trim().split('\n').length;
context.multiline = lineCount > 1;
return context;
}
function postProcessCodeContent(content: string, context: CodeContext): string {
let replacement = '<pre ngNonBindable';
if (!context.multiline) {
replacement += ' class="no-line-numbers"';
}
if (context.codeStyle) {
replacement += ` style="${context.codeStyle}"`;
} }
replacement += '>';
return content.replace('<pre>', replacement); return content.replace('<pre>', replacement);
} }

3
ui-ngx/src/styles.scss

@ -741,6 +741,9 @@ mat-label {
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
user-select: none; user-select: none;
&.multiline {
right: 44px;
}
p { p {
padding: 8px; padding: 8px;
top: 1px; top: 1px;

Loading…
Cancel
Save