Add color in result (#6)
continuous-integration/drone/push Build is passing Details

Co-authored-by: bastien ollier <bastien.ollier@etu.uca.fr>
Reviewed-on: #6
Reviewed-by: Clément FRÉVILLE <clement.freville2@etu.uca.fr>
Co-authored-by: Bastien OLLIER <bastien.ollier@noreply.codefirst.iut.uca.fr>
Co-committed-by: Bastien OLLIER <bastien.ollier@noreply.codefirst.iut.uca.fr>
pull/7/head
Bastien OLLIER 1 year ago committed by Clément FRÉVILLE
parent cf74413fc7
commit d41629abd0

23
package-lock.json generated

@ -21,6 +21,7 @@
"@emailjs/browser": "^3.12.1", "@emailjs/browser": "^3.12.1",
"@ngx-translate/core": "^15.0.0", "@ngx-translate/core": "^15.0.0",
"@ngx-translate/http-loader": "^8.0.0", "@ngx-translate/http-loader": "^8.0.0",
"ansi-to-html": "^0.7.2",
"codemirror": "^5.65.16", "codemirror": "^5.65.16",
"rxjs": "~7.8.1", "rxjs": "~7.8.1",
"sse.js": "^2.2.0", "sse.js": "^2.2.0",
@ -4070,6 +4071,28 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/ansi-to-html": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.7.2.tgz",
"integrity": "sha512-v6MqmEpNlxF+POuyhKkidusCHWWkaLcGRURzivcU3I9tv7k4JVhFcnukrM5Rlk2rUywdZuzYAZ+kbZqWCnfN3g==",
"dependencies": {
"entities": "^2.2.0"
},
"bin": {
"ansi-to-html": "bin/ansi-to-html"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/ansi-to-html/node_modules/entities": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/anymatch": { "node_modules/anymatch": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",

@ -23,6 +23,7 @@
"@emailjs/browser": "^3.12.1", "@emailjs/browser": "^3.12.1",
"@ngx-translate/core": "^15.0.0", "@ngx-translate/core": "^15.0.0",
"@ngx-translate/http-loader": "^8.0.0", "@ngx-translate/http-loader": "^8.0.0",
"ansi-to-html": "^0.7.2",
"codemirror": "^5.65.16", "codemirror": "^5.65.16",
"rxjs": "~7.8.1", "rxjs": "~7.8.1",
"sse.js": "^2.2.0", "sse.js": "^2.2.0",

@ -24,6 +24,7 @@ import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { TranslationService } from './services/translation.service'; import { TranslationService } from './services/translation.service';
import { SafeHTMLPipe } from './safe-html.pipe';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -37,8 +38,8 @@ import { TranslationService } from './services/translation.service';
FormComponent, FormComponent,
PrivacyPolicyComponent, PrivacyPolicyComponent,
TermsOfServiceComponent, TermsOfServiceComponent,
OurStoryComponent OurStoryComponent,
SafeHTMLPipe
], ],
imports: [ imports: [
BrowserModule, BrowserModule,

@ -14,20 +14,7 @@
</ngx-codemirror> </ngx-codemirror>
</div> </div>
<div> <pre [innerHTML]="resultContent | safeHTML"></pre>
<ngx-codemirror
[options]="{
theme: 'material',
lineNumbers: false,
lineWrapping: false,
mode: mode,
autofocus: true,
readOnly: true
}"
[(ngModel)]="resultContent"
>
</ngx-codemirror>
</div>
<div> <div>
<label for="language">Langage de programmation</label> <label for="language">Langage de programmation</label>

@ -3,6 +3,8 @@ import { Router } from "@angular/router";
import { CodeExecutionService } from "src/app/services/codeExecution.service"; import { CodeExecutionService } from "src/app/services/codeExecution.service";
import "codemirror/mode/shell/shell.js"; import "codemirror/mode/shell/shell.js";
import "codemirror/mode/clike/clike.js"; import "codemirror/mode/clike/clike.js";
import Convert from 'ansi-to-html';
// Exemple de code pour chaque langage autorisé // Exemple de code pour chaque langage autorisé
const codeDefaults = { const codeDefaults = {
@ -68,6 +70,13 @@ export class EditorComponent implements OnInit {
ngOnInit(): void { ngOnInit(): void {
// Appel à changeMode pour mettre à jour le contenu de l'éditeur et le mode // Appel à changeMode pour mettre à jour le contenu de l'éditeur et le mode
this.changeMode(); this.changeMode();
const convert = new Convert();
this.codeExecutionService.getResult().subscribe((result) => {
if (result.type !== 'exit') {
this.resultContent += convert.toHtml(result.text);
}
});
} }
// Change le langage de l'éditeur // Change le langage de l'éditeur
@ -160,8 +169,6 @@ export class EditorComponent implements OnInit {
this.codeExecutionService.executeCode(codeToExecute, this.mode); this.codeExecutionService.executeCode(codeToExecute, this.mode);
this.codeExecutionService.getResult().subscribe((result) => { this.resultContent = '';
this.resultContent = result;
});
} }
} }

@ -0,0 +1,8 @@
import { SafeHTMLPipe } from './safe-html.pipe';
describe('SafeHTMLPipe', () => {
it('create an instance', () => {
const pipe = new SafeHTMLPipe();
expect(pipe).toBeTruthy();
});
});

@ -0,0 +1,15 @@
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({
name: 'safeHTML',
})
export class SafeHTMLPipe implements PipeTransform {
constructor(protected sanitizer: DomSanitizer) {}
transform(value: unknown, ...args: unknown[]): unknown {
return this.sanitizer.bypassSecurityTrustHtml(value as string);
}
}

@ -1,16 +1,20 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { SSE } from 'sse.js'; import { SSE } from 'sse.js';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
export type ExecutionMessage = {
type: 'stdout' | 'stderr' | 'exit',
text: string
};
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
}) })
export class CodeExecutionService { export class CodeExecutionService {
private apiUrl = 'http://localhost:3000/run'; private apiUrl = 'http://localhost:3000/run';
private resultSubject = new Subject<string>(); private resultSubject = new Subject<ExecutionMessage>();
constructor(private http: HttpClient) {} constructor() {}
executeCode(code: string, language: string) { executeCode(code: string, language: string) {
const sse = new SSE(this.apiUrl, { const sse = new SSE(this.apiUrl, {
@ -25,13 +29,17 @@ export class CodeExecutionService {
sse.addEventListener('message', (event: MessageEvent<string>) => { sse.addEventListener('message', (event: MessageEvent<string>) => {
const result = event.data; const result = event.data;
// Émettre le résultat à tous les abonnés // @ts-ignore
const type = event.id;
const text = decodeURIComponent(result.replace(/%00/g, '')); const text = decodeURIComponent(result.replace(/%00/g, ''));
this.resultSubject.next(text); if (type === 'end') {
sse.close();
}
this.resultSubject.next({ type, text });
}); });
} }
getResult(): Observable<string> { getResult(): Observable<ExecutionMessage> {
return this.resultSubject.asObservable(); return this.resultSubject.asObservable();
} }
} }

@ -19,6 +19,7 @@
"target": "ES2022", "target": "ES2022",
"module": "ES2022", "module": "ES2022",
"useDefineForClassFields": false, "useDefineForClassFields": false,
"allowSyntheticDefaultImports": true,
"lib": [ "lib": [
"ES2022", "ES2022",
"dom" "dom"

Loading…
Cancel
Save