Skip to content

Commit 47910f4

Browse files
Highlights
1 parent 5446ca1 commit 47910f4

File tree

3 files changed

+109
-20
lines changed

3 files changed

+109
-20
lines changed

apps/codelab/src/app/admin/content/presentation-editor/wrappers/custom-component-editors/codelab-code-demo-console-editor/codelab-code-demo-console-editor.component.html

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<div class="wrapper">
22
<div class="file-editor">
33
<div *ngFor="let file of selectedFiles; let i = index">
4+
[{{ selection$ | async | json }}]$$
45
<mat-checkbox [(ngModel)]="file.selected" (ngModelChange)="update()">
56
<input
67
[ngModel]="file.name"
@@ -10,6 +11,28 @@
1011
<button mat-icon-button (click)="deleteFile(file.name)">
1112
<mat-icon>cancel</mat-icon>
1213
</button>
14+
<div>
15+
<div
16+
*ngFor="let highlight of file.highlights; let highlightIndex = index"
17+
>
18+
{{ highlight.text | slice: 0:20 }}
19+
<button
20+
mat-icon-button
21+
(click)="deleteHighlight(file, highlightIndex)"
22+
>
23+
<mat-icon>cancel</mat-icon>
24+
</button>
25+
</div>
26+
<ng-container *ngIf="selection$ | async as selection">
27+
<button
28+
mat-button
29+
*ngIf="selection.file === file.name"
30+
(click)="addHighlight(file, selection)"
31+
>
32+
Highlight selected
33+
</button>
34+
</ng-container>
35+
</div>
1336
</div>
1437
<button
1538
mat-button
@@ -34,6 +57,7 @@
3457
<code-demo
3558
[showPreview]="showPreview"
3659
[allowSwitchingFiles]="allowSwitchingFiles"
60+
[highlights]="highlights"
3761
[(ngModel)]="code"
3862
[displayFileName]="!allowSwitchingFiles"
3963
(ngModelChange)="update()"

apps/codelab/src/app/admin/content/presentation-editor/wrappers/custom-component-editors/codelab-code-demo-console-editor/codelab-code-demo-console-editor.component.ts

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
import { Component, Input, OnInit } from '@angular/core';
22
import { ContentService } from '../../../services/content.service';
33
import { ContentSlide, CustomBlock } from '../../../types';
4+
import { MonacoConfigService } from '@codelab/code-demos';
5+
import { Observable } from 'rxjs';
6+
import { Selection } from 'monaco-editor';
7+
import { tap } from 'rxjs/operators';
48

5-
interface SelectableFiles {
9+
interface SelectableFile {
610
selected: boolean;
711
name: string;
12+
highlights: Highlight[];
13+
}
14+
15+
interface Highlight {
16+
file: string;
17+
selection: Selection;
18+
prefix: string;
19+
text: string;
820
}
921

1022
@Component({
@@ -19,18 +31,48 @@ export class CodelabCodeDemoConsoleEditorComponent implements OnInit {
1931
@Input() block!: CustomBlock;
2032
@Input() slide!: ContentSlide;
2133
@Input() presentationId!: string;
22-
@Input() selectedFiles: SelectableFiles[] = [];
34+
@Input() selectedFiles: SelectableFile[] = [];
2335
@Input() showPreview = true;
2436
@Input() allowSwitchingFiles = true;
2537
@Input() displayFileName = false;
2638
readonly defaultNewFileName = 'new.ts';
2739

40+
readonly selection$ = new Observable<Highlight | undefined>(subscriber => {
41+
// TODO: Unsubscribe
42+
MonacoConfigService.monacoReady.then((monaco: any) => {
43+
monaco.editor.onDidCreateEditor(editor => {
44+
const subscription = editor.onDidChangeCursorPosition(() => {
45+
const selection = editor.getSelection();
46+
const text = editor.getModel().getValueInRange(selection);
47+
const match = editor.getModel().uri.match(/prefix\/(.+?)\/(.*)$/);
48+
if (text === '') {
49+
subscriber.next();
50+
return;
51+
}
52+
if (!match) {
53+
return;
54+
}
55+
const [, prefix, file] = match;
56+
57+
subscriber.next({ file, prefix, selection, text });
58+
});
59+
60+
editor.onDidDispose(() => subscription.dispose());
61+
});
62+
});
63+
});
64+
2865
openFiles: string[] = [];
66+
highlights: Record<string, Selection>;
2967

30-
ngOnInit() {
68+
async ngOnInit() {
3169
this.inferVars();
3270
}
33-
constructor(private readonly contentService: ContentService) {}
71+
72+
constructor(
73+
private readonly monacoConfigService: MonacoConfigService,
74+
private readonly contentService: ContentService
75+
) {}
3476

3577
update() {
3678
this.inferVars();
@@ -48,14 +90,23 @@ export class CodelabCodeDemoConsoleEditorComponent implements OnInit {
4890

4991
private inferVars() {
5092
this.files = Object.keys(this.code);
93+
5194
this.selectedFiles =
5295
this.selectedFiles.length === 0
5396
? this.files.map((name, i) => ({
5497
name,
55-
selected: i === 0
98+
selected: i === 0,
99+
highlights: []
56100
}))
57101
: this.selectedFiles;
58102

103+
this.highlights = this.selectedFiles.reduce((result, file) => {
104+
result[file.name] = file.highlights.map(h => h.selection);
105+
return result;
106+
}, {});
107+
108+
console.log(this.highlights);
109+
59110
this.openFiles = this.selectedFiles
60111
.filter(file => file.selected)
61112
.map(({ name }) => name);
@@ -75,7 +126,8 @@ export class CodelabCodeDemoConsoleEditorComponent implements OnInit {
75126
if (!this.code[this.defaultNewFileName]) {
76127
this.selectedFiles.push({
77128
name: this.defaultNewFileName,
78-
selected: false
129+
selected: false,
130+
highlights: []
79131
});
80132
this.code[this.defaultNewFileName] = '// code';
81133
}
@@ -85,4 +137,14 @@ export class CodelabCodeDemoConsoleEditorComponent implements OnInit {
85137
delete this.code[name];
86138
this.selectedFiles = this.selectedFiles.filter(file => file.name !== name);
87139
}
140+
141+
addHighlight(file: SelectableFile, highlight: Highlight) {
142+
file.highlights.push(JSON.parse(JSON.stringify(highlight)));
143+
this.update();
144+
}
145+
146+
deleteHighlight(file: SelectableFile, highlightIndex: number) {
147+
file.highlights.splice(highlightIndex, 1);
148+
this.update();
149+
}
88150
}

libs/code-demos/src/lib/code-demo-editor/directives/code-demo-editor.highlight.directive.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,14 @@ export class CodeDemoEditorHighlightDirective
3939

4040
const editor = this.editorInjector.editor;
4141
if (editor) {
42-
if (!this.codeDemoHighlight) {
42+
if (!this.codeDemoHighlight || !editor.getModel()) {
4343
return;
4444
}
4545

4646
if (!Array.isArray(this.codeDemoHighlight)) {
4747
this.codeDemoHighlight = [this.codeDemoHighlight];
4848
}
4949

50-
if (!editor.getModel()) {
51-
return;
52-
}
5350
const code = editor.getModel().getValue();
5451

5552
if (!code.length) {
@@ -61,17 +58,23 @@ export class CodeDemoEditorHighlightDirective
6158
typeof match !== 'string' && match.match ? match : { match }
6259
)
6360
.reduce((ranges, { match, className }) => {
64-
const { indexStart, lineStart, indexEnd, lineEnd } = findPosition(
65-
code,
66-
match
67-
);
61+
let range: [number, number, number, number];
62+
if (match.endColumn) {
63+
range = [
64+
match.selectionStartLineNumber,
65+
match.selectionStartColumn,
66+
match.endLineNumber,
67+
match.endColumn
68+
];
69+
} else {
70+
const position = findPosition(code, match);
71+
72+
const { indexStart, lineStart, indexEnd, lineEnd } = position;
73+
range = [lineStart, indexStart, lineEnd, indexEnd];
74+
}
75+
6876
ranges.push({
69-
range: new this.monacoConfigService.monaco.Range(
70-
lineStart,
71-
indexStart,
72-
lineEnd,
73-
indexEnd
74-
),
77+
range: new this.monacoConfigService.monaco.Range(...range),
7578
options: { inlineClassName: className || 'highlighted-code' }
7679
});
7780

0 commit comments

Comments
 (0)