Add the work management
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
90f83ec698
commit
0e97f37bff
@ -1,26 +1,29 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { EditorComponent } from './components/editor/editor.component';
|
||||
import { LandingPageComponent } from './components/landing-page/landing-page.component';
|
||||
import { DocumentationComponent } from './components/documentation/documentation.component';
|
||||
import { FormComponent } from './components/form/form.component';
|
||||
import { TermsOfServiceComponent } from './components/terms-of-service/terms-of-service.component';
|
||||
import { OurStoryComponent } from './components/our-story/our-story.component';
|
||||
import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-policy.component';
|
||||
import {NgModule} from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {EditorComponent} from './components/editor/editor.component';
|
||||
import {LandingPageComponent} from './components/landing-page/landing-page.component';
|
||||
import {DocumentationComponent} from './components/documentation/documentation.component';
|
||||
import {FormComponent} from './components/form/form.component';
|
||||
import {TermsOfServiceComponent} from './components/terms-of-service/terms-of-service.component';
|
||||
import {OurStoryComponent} from './components/our-story/our-story.component';
|
||||
import {PrivacyPolicyComponent} from './components/privacy-policy/privacy-policy.component';
|
||||
import {WorksListComponent} from "./components/works-list/works-list.component";
|
||||
|
||||
// Toutes les routes de l'application sont définies ici
|
||||
const routes: Routes = [
|
||||
{ path: '', component: LandingPageComponent },
|
||||
{ path: 'editor', component: EditorComponent },
|
||||
{ path: 'documentation', component: DocumentationComponent },
|
||||
{ path: 'contact', component: FormComponent },
|
||||
{ path: 'our-story', component: OurStoryComponent },
|
||||
{ path: 'terms-of-service', component: TermsOfServiceComponent },
|
||||
{ path: 'privacy-policy', component: PrivacyPolicyComponent },
|
||||
{path: '', component: LandingPageComponent},
|
||||
{path: 'editor', component: EditorComponent},
|
||||
{path: 'documentation', component: DocumentationComponent},
|
||||
{path: 'contact', component: FormComponent},
|
||||
{path: 'our-story', component: OurStoryComponent},
|
||||
{path: 'terms-of-service', component: TermsOfServiceComponent},
|
||||
{path: 'privacy-policy', component: PrivacyPolicyComponent},
|
||||
{path: 'works', component: WorksListComponent},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule],
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AppRoutingModule {}
|
||||
export class AppRoutingModule {
|
||||
}
|
||||
|
@ -1,107 +1,112 @@
|
||||
<div id="editor">
|
||||
<div id="editor-bar-header">
|
||||
<div class="editor-section-bar-header">
|
||||
<div class="param-editor">
|
||||
<label for="fileInput">
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M1 5C1 3.34315 2.34315 2 4 2H8.55848C9.84977 2 10.9962 2.82629 11.4045 4.05132L11.7208 5H20C21.1046 5 22 5.89543 22 7V9.00961C23.1475 9.12163 23.9808 10.196 23.7695 11.3578L22.1332 20.3578C21.9603 21.3087 21.132 22 20.1654 22H3C1.89543 22 1 21.1046 1 20V5ZM20 9V7H11.7208C10.8599 7 10.0956 6.44914 9.82339 5.63246L9.50716 4.68377C9.37105 4.27543 8.98891 4 8.55848 4H4C3.44772 4 3 4.44772 3 5V12.2709L3.35429 10.588C3.54913 9.66249 4.36562 9 5.31139 9H20ZM3.36634 20C3.41777 19.9109 3.4562 19.8122 3.47855 19.706L5.31139 11L21 11H21.8018L20.1654 20L3.36634 20Z"
|
||||
fill="#000000"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</label>
|
||||
<input
|
||||
style="display: none"
|
||||
type="file"
|
||||
id="fileInput"
|
||||
(change)="loadFromFile($event)" />
|
||||
</div>
|
||||
<div id="editor-bar-header">
|
||||
<div class="editor-section-bar-header">
|
||||
<div class="param-editor">
|
||||
<label for="fileInput">
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M1 5C1 3.34315 2.34315 2 4 2H8.55848C9.84977 2 10.9962 2.82629 11.4045 4.05132L11.7208 5H20C21.1046 5 22 5.89543 22 7V9.00961C23.1475 9.12163 23.9808 10.196 23.7695 11.3578L22.1332 20.3578C21.9603 21.3087 21.132 22 20.1654 22H3C1.89543 22 1 21.1046 1 20V5ZM20 9V7H11.7208C10.8599 7 10.0956 6.44914 9.82339 5.63246L9.50716 4.68377C9.37105 4.27543 8.98891 4 8.55848 4H4C3.44772 4 3 4.44772 3 5V12.2709L3.35429 10.588C3.54913 9.66249 4.36562 9 5.31139 9H20ZM3.36634 20C3.41777 19.9109 3.4562 19.8122 3.47855 19.706L5.31139 11L21 11H21.8018L20.1654 20L3.36634 20Z"
|
||||
fill="#000000"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</label>
|
||||
<input
|
||||
style="display: none"
|
||||
type="file"
|
||||
id="fileInput"
|
||||
(change)="loadFromFile($event)"/>
|
||||
</div>
|
||||
|
||||
<div class="param-editor">
|
||||
<button class="button-icon" type="button" (click)="saveToFile()">
|
||||
<svg
|
||||
width="800px"
|
||||
height="800px"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M3 15C3 17.8284 3 19.2426 3.87868 20.1213C4.75736 21 6.17157 21 9 21H15C17.8284 21 19.2426 21 20.1213 20.1213C21 19.2426 21 17.8284 21 15"
|
||||
stroke="#1C274C"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M12 3V16M12 16L16 11.625M12 16L8 11.625"
|
||||
stroke="#1C274C"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="editor-section-bar-header">
|
||||
@if (errorMessage) {
|
||||
<div class="param-editor">
|
||||
<p style="color: red">{{ errorMessage }}</p>
|
||||
</div>
|
||||
}
|
||||
<div class="param-editor">
|
||||
<button class="button-icon" type="button" (click)="saveToFile()">
|
||||
<svg
|
||||
width="800px"
|
||||
height="800px"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M3 15C3 17.8284 3 19.2426 3.87868 20.1213C4.75736 21 6.17157 21 9 21H15C17.8284 21 19.2426 21 20.1213 20.1213C21 19.2426 21 17.8284 21 15"
|
||||
stroke="#1C274C"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"/>
|
||||
<path
|
||||
d="M12 3V16M12 16L16 11.625M12 16L8 11.625"
|
||||
stroke="#1C274C"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="param-editor">
|
||||
<button class="button-icon" type="button" (click)="addToDatabase()">
|
||||
ADD BDD
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="editor-section-bar-header">
|
||||
@if (errorMessage) {
|
||||
<div class="param-editor">
|
||||
<p style="color: red">{{ errorMessage }}</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
<select id="language" [(ngModel)]="selectedLanguage">
|
||||
@for (language of languages; track language.name) {
|
||||
<option [ngValue]="language">{{ language.name }}</option>
|
||||
}
|
||||
</select>
|
||||
<select id="language" [(ngModel)]="selectedLanguage">
|
||||
@for (language of languages; track language.name) {
|
||||
<option [ngValue]="language">{{ language.name }}</option>
|
||||
}
|
||||
</select>
|
||||
|
||||
<div class="param-editor">
|
||||
<button
|
||||
class="button-icon button-run"
|
||||
type="button"
|
||||
(click)="onRunButtonClicked()"
|
||||
[disabled]="isLoaded">
|
||||
<div>RUN</div>
|
||||
<svg
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="#000000">
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path
|
||||
d="M2.78 2L2 2.41v12l.78.42 9-6V8l-9-6zM3 13.48V3.35l7.6 5.07L3 13.48z"></path>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M6 14.683l8.78-5.853V8L6 2.147V3.35l7.6 5.07L6 13.48v1.203z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="param-editor">
|
||||
<button
|
||||
class="button-icon button-run"
|
||||
type="button"
|
||||
(click)="onRunButtonClicked()"
|
||||
[disabled]="isLoaded">
|
||||
<div>RUN</div>
|
||||
<svg
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="#000000">
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path
|
||||
d="M2.78 2L2 2.41v12l.78.42 9-6V8l-9-6zM3 13.48V3.35l7.6 5.07L3 13.48z"></path>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M6 14.683l8.78-5.853V8L6 2.147V3.35l7.6 5.07L6 13.48v1.203z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editor-center">
|
||||
<div class="editor-child-element">
|
||||
<codemirror6-editor [(ngModel)]="editorContent" [extensions]="extensions">
|
||||
</codemirror6-editor>
|
||||
</div>
|
||||
<div class="editor-child-element">
|
||||
<pre id="resultDiv" [innerHTML]="resultContent | safeHTML"></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="editor-center">
|
||||
<div class="editor-child-element">
|
||||
<codemirror6-editor [(ngModel)]="editorContent" [extensions]="extensions">
|
||||
</codemirror6-editor>
|
||||
</div>
|
||||
<div class="editor-child-element">
|
||||
<pre id="resultDiv" [innerHTML]="resultContent | safeHTML"></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,179 +1,190 @@
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import { CodeExecutionService } from 'src/app/services/codeExecution.service';
|
||||
import { Compartment } from '@codemirror/state';
|
||||
import { CodeMirrorComponent } from '@sandkasten/codemirror6-editor';
|
||||
import { LanguageDescription } from '@codemirror/language';
|
||||
import { CODE_DEFAULTS, LANGUAGES } from '../languages';
|
||||
import { SafeHTMLPipe } from '../../safe-html.pipe';
|
||||
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
|
||||
import {Component, ViewChild} from '@angular/core';
|
||||
import {CodeExecutionService} from 'src/app/services/codeExecution.service';
|
||||
import {Compartment} from '@codemirror/state';
|
||||
import {CodeMirrorComponent} from '@sandkasten/codemirror6-editor';
|
||||
import {LanguageDescription} from '@codemirror/language';
|
||||
import {CODE_DEFAULTS, LANGUAGES} from '../languages';
|
||||
import {SafeHTMLPipe} from '../../safe-html.pipe';
|
||||
import {ReactiveFormsModule, FormsModule} from '@angular/forms';
|
||||
import {
|
||||
keymap,
|
||||
highlightSpecialChars,
|
||||
drawSelection,
|
||||
highlightActiveLine,
|
||||
dropCursor,
|
||||
rectangularSelection,
|
||||
crosshairCursor,
|
||||
lineNumbers,
|
||||
highlightActiveLineGutter,
|
||||
gutter,
|
||||
keymap,
|
||||
highlightSpecialChars,
|
||||
drawSelection,
|
||||
highlightActiveLine,
|
||||
dropCursor,
|
||||
rectangularSelection,
|
||||
crosshairCursor,
|
||||
lineNumbers,
|
||||
highlightActiveLineGutter,
|
||||
gutter,
|
||||
} from '@codemirror/view';
|
||||
import { Extension, EditorState } from '@codemirror/state';
|
||||
import {Extension, EditorState} from '@codemirror/state';
|
||||
import {
|
||||
defaultHighlightStyle,
|
||||
syntaxHighlighting,
|
||||
indentOnInput,
|
||||
bracketMatching,
|
||||
foldGutter,
|
||||
foldKeymap,
|
||||
defaultHighlightStyle,
|
||||
syntaxHighlighting,
|
||||
indentOnInput,
|
||||
bracketMatching,
|
||||
foldGutter,
|
||||
foldKeymap,
|
||||
} from '@codemirror/language';
|
||||
import { defaultKeymap, history, historyKeymap } from '@codemirror/commands';
|
||||
import { searchKeymap, highlightSelectionMatches } from '@codemirror/search';
|
||||
import {defaultKeymap, history, historyKeymap} from '@codemirror/commands';
|
||||
import {searchKeymap, highlightSelectionMatches} from '@codemirror/search';
|
||||
import {
|
||||
autocompletion,
|
||||
completionKeymap,
|
||||
closeBrackets,
|
||||
closeBracketsKeymap,
|
||||
autocompletion,
|
||||
completionKeymap,
|
||||
closeBrackets,
|
||||
closeBracketsKeymap,
|
||||
} from '@codemirror/autocomplete';
|
||||
import { lintKeymap } from '@codemirror/lint';
|
||||
import {lintKeymap} from '@codemirror/lint';
|
||||
import {WorksService} from "../../services/works.service";
|
||||
|
||||
const basicSetup: Extension = (() => [
|
||||
highlightActiveLineGutter(),
|
||||
highlightSpecialChars(),
|
||||
history(),
|
||||
foldGutter(),
|
||||
drawSelection(),
|
||||
dropCursor(),
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
indentOnInput(),
|
||||
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
||||
bracketMatching(),
|
||||
closeBrackets(),
|
||||
autocompletion(),
|
||||
rectangularSelection(),
|
||||
crosshairCursor(),
|
||||
highlightActiveLine(),
|
||||
highlightSelectionMatches(),
|
||||
keymap.of([
|
||||
...closeBracketsKeymap,
|
||||
...defaultKeymap,
|
||||
...searchKeymap,
|
||||
...historyKeymap,
|
||||
...foldKeymap,
|
||||
...completionKeymap,
|
||||
...lintKeymap,
|
||||
]),
|
||||
highlightActiveLineGutter(),
|
||||
highlightSpecialChars(),
|
||||
history(),
|
||||
foldGutter(),
|
||||
drawSelection(),
|
||||
dropCursor(),
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
indentOnInput(),
|
||||
syntaxHighlighting(defaultHighlightStyle, {fallback: true}),
|
||||
bracketMatching(),
|
||||
closeBrackets(),
|
||||
autocompletion(),
|
||||
rectangularSelection(),
|
||||
crosshairCursor(),
|
||||
highlightActiveLine(),
|
||||
highlightSelectionMatches(),
|
||||
keymap.of([
|
||||
...closeBracketsKeymap,
|
||||
...defaultKeymap,
|
||||
...searchKeymap,
|
||||
...historyKeymap,
|
||||
...foldKeymap,
|
||||
...completionKeymap,
|
||||
...lintKeymap,
|
||||
]),
|
||||
])();
|
||||
|
||||
@Component({
|
||||
selector: 'app-editor',
|
||||
templateUrl: './editor.component.html',
|
||||
styleUrls: ['./editor.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
CodeMirrorComponent,
|
||||
ReactiveFormsModule,
|
||||
FormsModule,
|
||||
SafeHTMLPipe,
|
||||
],
|
||||
selector: 'app-editor',
|
||||
templateUrl: './editor.component.html',
|
||||
styleUrls: ['./editor.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
CodeMirrorComponent,
|
||||
ReactiveFormsModule,
|
||||
FormsModule,
|
||||
SafeHTMLPipe,
|
||||
],
|
||||
})
|
||||
export class EditorComponent {
|
||||
isLoaded: boolean = false; // Pour vérifier si le chargement est terminé
|
||||
|
||||
readonly languages: LanguageDescription[] = LANGUAGES;
|
||||
// Mode par défaut
|
||||
private _selectedLanguage = this.languages.find(
|
||||
(lang) => lang.name === 'JavaScript'
|
||||
)!;
|
||||
get selectedLanguage(): LanguageDescription {
|
||||
return this._selectedLanguage;
|
||||
}
|
||||
set selectedLanguage(value: LanguageDescription) {
|
||||
this._selectedLanguage = value;
|
||||
if (value.name in CODE_DEFAULTS) {
|
||||
this.editorContent =
|
||||
CODE_DEFAULTS[value.name as keyof typeof CODE_DEFAULTS];
|
||||
isLoaded: boolean = false; // Pour vérifier si le chargement est terminé
|
||||
|
||||
readonly languages: LanguageDescription[] = LANGUAGES;
|
||||
// Mode par défaut
|
||||
private _selectedLanguage = this.languages.find(
|
||||
(lang) => lang.name === 'JavaScript'
|
||||
)!;
|
||||
get selectedLanguage(): LanguageDescription {
|
||||
return this._selectedLanguage;
|
||||
}
|
||||
|
||||
set selectedLanguage(value: LanguageDescription) {
|
||||
this._selectedLanguage = value;
|
||||
if (value.name in CODE_DEFAULTS) {
|
||||
this.editorContent =
|
||||
CODE_DEFAULTS[value.name as keyof typeof CODE_DEFAULTS];
|
||||
}
|
||||
this.selectedLanguage.load().then((language) => {
|
||||
this.codemirror.editor?.dispatch({
|
||||
effects: this.languageCompartment.reconfigure(language),
|
||||
});
|
||||
});
|
||||
}
|
||||
this.selectedLanguage.load().then((language) => {
|
||||
this.codemirror.editor?.dispatch({
|
||||
effects: this.languageCompartment.reconfigure(language),
|
||||
});
|
||||
});
|
||||
}
|
||||
private _linesNumbers: boolean = true;
|
||||
get linesNumbers() {
|
||||
return this._linesNumbers;
|
||||
}
|
||||
set linesNumbers(lines: boolean) {
|
||||
this._linesNumbers = lines;
|
||||
this.codemirror.editor?.dispatch({
|
||||
effects: this.gutterCompartment.reconfigure(
|
||||
lines ? lineNumbers() : gutter({})
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
// Contenu de l'éditeur que l'on passera au serveur
|
||||
editorContent: string =
|
||||
CODE_DEFAULTS[this.selectedLanguage.name as keyof typeof CODE_DEFAULTS];
|
||||
resultContent: string = '';
|
||||
|
||||
// Message d'erreur
|
||||
errorMessage: string = '';
|
||||
|
||||
@ViewChild(CodeMirrorComponent) private codemirror!: CodeMirrorComponent;
|
||||
|
||||
private readonly languageCompartment = new Compartment();
|
||||
private readonly gutterCompartment = new Compartment();
|
||||
protected readonly extensions: Extension[] = [
|
||||
basicSetup,
|
||||
this.gutterCompartment.of(lineNumbers()),
|
||||
this.languageCompartment.of(this.selectedLanguage.support!),
|
||||
];
|
||||
|
||||
constructor(private codeExecutionService: CodeExecutionService) {}
|
||||
|
||||
// Efface le contenu de l'éditeur
|
||||
clear(): void {
|
||||
this.editorContent = '';
|
||||
}
|
||||
|
||||
onRunButtonClicked() {
|
||||
// Le code à exécuter est le contenu de l'éditeur
|
||||
const codeToExecute = this.editorContent;
|
||||
|
||||
this.codeExecutionService.executeCode(
|
||||
codeToExecute,
|
||||
this.selectedLanguage.name
|
||||
);
|
||||
|
||||
this.resultContent = '';
|
||||
}
|
||||
|
||||
loadFromFile(event: Event) {
|
||||
const file = (event.target as HTMLInputElement).files![0];
|
||||
for (const language of this.languages) {
|
||||
if (language.extensions.some((ext) => file.name.endsWith(`.${ext}`))) {
|
||||
this.selectedLanguage = language;
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
this.editorContent = event.target!.result as string;
|
||||
this.errorMessage = '';
|
||||
};
|
||||
reader.readAsText(file);
|
||||
return;
|
||||
}
|
||||
|
||||
private _linesNumbers: boolean = true;
|
||||
get linesNumbers() {
|
||||
return this._linesNumbers;
|
||||
}
|
||||
const extensions = this.languages.flatMap((lang) => lang.extensions);
|
||||
this.errorMessage = `Unsupported language. Please select one of the following languages: ${extensions.join(', ')}.`;
|
||||
console.error(this.errorMessage);
|
||||
}
|
||||
|
||||
saveToFile() {
|
||||
const blob = new Blob([this.editorContent], { type: 'text/plain' });
|
||||
const a = document.createElement('a');
|
||||
a.download = `code.${this.selectedLanguage.extensions![0]}`;
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.click();
|
||||
}
|
||||
|
||||
set linesNumbers(lines: boolean) {
|
||||
this._linesNumbers = lines;
|
||||
this.codemirror.editor?.dispatch({
|
||||
effects: this.gutterCompartment.reconfigure(
|
||||
lines ? lineNumbers() : gutter({})
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
// Contenu de l'éditeur que l'on passera au serveur
|
||||
editorContent: string =
|
||||
CODE_DEFAULTS[this.selectedLanguage.name as keyof typeof CODE_DEFAULTS];
|
||||
resultContent: string = '';
|
||||
|
||||
// Message d'erreur
|
||||
errorMessage: string = '';
|
||||
|
||||
@ViewChild(CodeMirrorComponent) private codemirror!: CodeMirrorComponent;
|
||||
|
||||
private readonly languageCompartment = new Compartment();
|
||||
private readonly gutterCompartment = new Compartment();
|
||||
protected readonly extensions: Extension[] = [
|
||||
basicSetup,
|
||||
this.gutterCompartment.of(lineNumbers()),
|
||||
this.languageCompartment.of(this.selectedLanguage.support!),
|
||||
];
|
||||
|
||||
constructor(private codeExecutionService: CodeExecutionService, protected workService: WorksService) {
|
||||
}
|
||||
|
||||
// Efface le contenu de l'éditeur
|
||||
clear(): void {
|
||||
this.editorContent = '';
|
||||
}
|
||||
|
||||
onRunButtonClicked() {
|
||||
// Le code à exécuter est le contenu de l'éditeur
|
||||
const codeToExecute = this.editorContent;
|
||||
|
||||
this.codeExecutionService.executeCode(
|
||||
codeToExecute,
|
||||
this.selectedLanguage.name
|
||||
);
|
||||
|
||||
this.resultContent = '';
|
||||
}
|
||||
|
||||
loadFromFile(event: Event) {
|
||||
const file = (event.target as HTMLInputElement).files![0];
|
||||
for (const language of this.languages) {
|
||||
if (language.extensions.some((ext) => file.name.endsWith(`.${ext}`))) {
|
||||
this.selectedLanguage = language;
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
this.editorContent = event.target!.result as string;
|
||||
this.errorMessage = '';
|
||||
};
|
||||
reader.readAsText(file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const extensions = this.languages.flatMap((lang) => lang.extensions);
|
||||
this.errorMessage = `Unsupported language. Please select one of the following languages: ${extensions.join(', ')}.`;
|
||||
console.error(this.errorMessage);
|
||||
}
|
||||
|
||||
saveToFile() {
|
||||
const blob = new Blob([this.editorContent], {type: 'text/plain'});
|
||||
const a = document.createElement('a');
|
||||
a.download = `code.${this.selectedLanguage.extensions![0]}`;
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.click();
|
||||
}
|
||||
|
||||
addToDatabase() {
|
||||
this.workService.postWorkCode(this.editorContent);
|
||||
}
|
||||
|
||||
protected readonly console = console;
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
<h2>Works</h2>
|
||||
|
||||
<ul>
|
||||
<li *ngFor="let work of works">
|
||||
{{ work.id_work }} - {{ work.link }} - {{ work.content }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<form #addBookForm="ngForm" (ngSubmit)="onSubmit(addBookForm)">
|
||||
<div class="form-group">
|
||||
<label for="link">Link</label>
|
||||
<input type="text" class="form-control" id="link" name="link" ngModel required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="content">Content</label>
|
||||
<input type="text" class="form-control" id="content" name="content" ngModel required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</form>
|
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { WorksListComponent } from './works-list.component';
|
||||
|
||||
describe('WorksListComponent', () => {
|
||||
let component: WorksListComponent;
|
||||
let fixture: ComponentFixture<WorksListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [WorksListComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(WorksListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,30 @@
|
||||
import {Component} from '@angular/core';
|
||||
import {Work} from "../../models/work.model";
|
||||
import {WorksService} from "../../services/works.service";
|
||||
import {NgForOf} from "@angular/common";
|
||||
import {FormsModule, NgForm} from "@angular/forms";
|
||||
|
||||
@Component({
|
||||
selector: 'app-works-list',
|
||||
standalone: true,
|
||||
imports: [
|
||||
NgForOf,
|
||||
FormsModule
|
||||
],
|
||||
templateUrl: './works-list.component.html',
|
||||
styleUrl: './works-list.component.css'
|
||||
})
|
||||
export class WorksListComponent {
|
||||
works: Work[] = [];
|
||||
|
||||
constructor(protected workService: WorksService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.workService.getWorks().subscribe((response: Work[]) => this.works = response)
|
||||
}
|
||||
|
||||
onSubmit(form: NgForm) {
|
||||
this.workService.postWork(form);
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
export interface Work {
|
||||
id_work: number,
|
||||
link: string,
|
||||
user_id: number,
|
||||
language_id: number,
|
||||
content: string
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Work} from "../models/work.model";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {Observable} from "rxjs";
|
||||
import {NgForm} from "@angular/forms";
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class WorksService {
|
||||
API_URL = 'http://127.0.0.1:3000'
|
||||
|
||||
private works: Work[] = [];
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
}
|
||||
|
||||
getWorks(): Observable<any> {
|
||||
return this.http.get(`${this.API_URL}/works`);
|
||||
}
|
||||
|
||||
postWork(form: NgForm): void {
|
||||
let body = {link: form.value.link, id_user: 1, id_language: 1, code: form.value.content}
|
||||
this.http.post<any>(`${this.API_URL}/works`, body).subscribe();
|
||||
}
|
||||
|
||||
postWorkCode(code: string): void {
|
||||
let body = {link: 'TODO', id_user: 1, id_language: 1, code: code}
|
||||
this.http.post<any>(`${this.API_URL}/works`, body).subscribe();
|
||||
}
|
||||
}
|
Loading…
Reference in new issue