diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts
index e0ca603..29b9581 100644
--- a/src/app/app.routes.ts
+++ b/src/app/app.routes.ts
@@ -1,6 +1,5 @@
import { Routes } from '@angular/router';
import { EditorComponent } from './components/editor/editor.component';
-import { EditorLiveComponent } from './components/editor-live/editor-live.component';
import { LandingPageComponent } from './components/landing-page/landing-page.component';
import { DocumentationComponent } from './components/documentation/documentation.component';
import { FormComponent } from './components/form/form.component';
@@ -12,7 +11,7 @@ import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-poli
export const routes: Routes = [
{ path: '', component: LandingPageComponent },
{ path: 'editor', component: EditorComponent },
- { path: 'editor-live/:idRoom', component: EditorLiveComponent },
+ { path: 'editor-live/:idRoom', component: EditorComponent },
{ path: 'documentation', component: DocumentationComponent },
{ path: 'contact', component: FormComponent },
{ path: 'our-story', component: OurStoryComponent },
diff --git a/src/app/components/editor-live/editor-live.component.html b/src/app/components/editor-live/editor-live.component.html
deleted file mode 100644
index e1a834e..0000000
--- a/src/app/components/editor-live/editor-live.component.html
+++ /dev/null
@@ -1,115 +0,0 @@
-
diff --git a/src/app/components/editor-live/editor-live.component.scss b/src/app/components/editor-live/editor-live.component.scss
deleted file mode 100644
index 3e19580..0000000
--- a/src/app/components/editor-live/editor-live.component.scss
+++ /dev/null
@@ -1,85 +0,0 @@
-#editor-bar-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 10px;
- color: #fff;
-}
-
-.editor-section-bar-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 1rem;
-}
-
-.button-icon {
- border: 0;
- background: transparent;
- cursor: pointer;
-}
-
-svg {
- width: 30px;
- height: auto;
- aspect-ratio: 1;
- cursor: pointer;
-}
-
-.button-run {
- display: flex;
- align-items: center;
- justify-content: space-between;
- background-color: #04aa6d;
- border: none;
- color: white;
- padding: 12px 16px;
- font-size: 16px;
- width: 100px;
- cursor: pointer;
- border-radius: 10px;
-}
-
-.button-join {
- background-color: #1c53bf;
- border: none;
- color: white;
- padding: 12px 16px;
- font-size: 16px;
- width: 100px;
- cursor: pointer;
- border-radius: 10px;
-}
-
-select {
- background-color: #0000f0;
- border: none;
- color: white;
- padding: 12px 16px;
- font-size: 16px;
- cursor: pointer;
- border-radius: 10px;
-}
-
-/*editor*/
-
-.editor-center {
- height: 700px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin: 0px 0px 0px 0px;
-}
-
-.editor-child-element {
- min-height: 100px;
- height: 100%;
- width: 1000px;
- background-color: black;
- color: #fff;
- border-right: 10px solid gray;
-}
-
-::ng-deep .codemirror6-editor {
- height: 100%;
-}
diff --git a/src/app/components/editor-live/editor-live.component.spec.ts b/src/app/components/editor-live/editor-live.component.spec.ts
deleted file mode 100644
index aec1b0b..0000000
--- a/src/app/components/editor-live/editor-live.component.spec.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { EditorLiveComponent } from './editor-live.component';
-
-describe('EditorLiveComponent', () => {
- let component: EditorLiveComponent;
- let fixture: ComponentFixture;
-
- beforeEach(() => {
- TestBed.configureTestingModule({
- imports: [EditorLiveComponent],
- });
- fixture = TestBed.createComponent(EditorLiveComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/src/app/components/editor-live/editor-live.component.ts b/src/app/components/editor-live/editor-live.component.ts
deleted file mode 100644
index 4fea997..0000000
--- a/src/app/components/editor-live/editor-live.component.ts
+++ /dev/null
@@ -1,328 +0,0 @@
-import { Component, Input, ViewChild } from '@angular/core';
-import { CodeExecutionService } from 'src/app/services/codeExecution.service';
-import { Compartment, StateEffect } 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,
-} from '@codemirror/view';
-import { Extension, EditorState } from '@codemirror/state';
-import {
- defaultHighlightStyle,
- syntaxHighlighting,
- indentOnInput,
- bracketMatching,
- foldGutter,
- foldKeymap,
-} from '@codemirror/language';
-import { defaultKeymap, history, historyKeymap } from '@codemirror/commands';
-import { searchKeymap, highlightSelectionMatches } from '@codemirror/search';
-import {
- autocompletion,
- completionKeymap,
- closeBrackets,
- closeBracketsKeymap,
-} from '@codemirror/autocomplete';
-import { lintKeymap } from '@codemirror/lint';
-
-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,
- ]),
-])();
-
-@Component({
- selector: 'app-editor-live',
- templateUrl: './editor-live.component.html',
- styleUrls: ['./editor-live.component.scss'],
- standalone: true,
- imports: [
- CodeMirrorComponent,
- ReactiveFormsModule,
- FormsModule,
- SafeHTMLPipe,
- ],
-})
-export class EditorLiveComponent {
- 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),
- });
- });
- }
- 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!),
- ];
-
- private client: WebSocket | undefined;
- @Input()
- set idRoom(idRoom: string) {
- this.client = new WebSocket(`ws://127.0.0.1:3000/live/${idRoom}`);
- this.client.addEventListener('open', async () => {
- let conn = new Connection(this.client!);
- console.log('open')
- let {version, doc} = await getDocument(conn);
- console.log('res')
- this.codemirror.editor?.dispatch({
- changes: {
- from: 0,
- to: this.codemirror.editor.state.doc.length,
- insert: doc
- }
- })
- this.codemirror.editor?.dispatch({
- effects: StateEffect.appendConfig.of([peerExtension(version, conn)]),
- })
- });
- }
-
-
- 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;
- }
- }
- 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();
- }
-}
-
-/*live*/
-import { ChangeSet, Text } from '@codemirror/state';
-import {EditorView} from "codemirror"
-import { Update, collab, getSyncedVersion, receiveUpdates, sendableUpdates } from '@codemirror/collab';
-import { ViewPlugin, ViewUpdate } from '@codemirror/view';
-
-class Connection {
- private requestId = 0;
- private resolves: Record void> = {};
-
- constructor(private client: WebSocket) {
- client.addEventListener('message', (event) => {
- const response = JSON.parse(event.data);
- if ('_request' in response) {
- const resolve = this.resolves[response._request];
- if (resolve) {
- resolve(response.payload);
- } else {
- console.error('Received response for unknown or already used request', response._request);
- }
- } else {
- console.error('Received invalid response', response._request);
- }
- })
- }
-
- request(body: Record): Promise {
- body['_request'] = this.requestId;
- this.client.send(JSON.stringify(body));
- return new Promise((resolve) => this.resolves[this.requestId++] = resolve);
- }
-}
-
-function pushUpdates(
- connection: Connection,
- version: number,
- fullUpdates: readonly Update[]
-): Promise {
- // Strip off transaction data
- let updates = fullUpdates.map(u => ({
- clientID: u.clientID,
- changes: u.changes.toJSON()
- }));
- console.log("test1");
- return connection.request({type: "pushUpdates", version, updates});
-}
-
-function pullUpdates(
- connection: Connection,
- version: number
-): Promise {
- console.log("test2");
-
- return connection.request({type: "pullUpdates", version})
- .then(updates => updates.map((u: any) => ({
- changes: ChangeSet.fromJSON(u.changes),
- clientID: u.clientID
- })));
-}
-
-function getDocument(
- connection: Connection
-): Promise<{version: number, doc: Text}> {
- console.log("test3");
-
- return connection.request({ type: "getDocument" }).then(data => ({
- version: data.version,
- doc: Text.of(data.doc.split("\n"))
- }));
-}
-
-function peerExtension(startVersion: number, connection: Connection) {
- console.log(connection)
- let plugin = ViewPlugin.fromClass(class {
- private pushing = false
- private done = false
-
- constructor(private view: EditorView) { this.pull() }
-
- update(update: ViewUpdate) {
- if (update.docChanged) this.push()
- }
-
- async push() {
- let updates = sendableUpdates(this.view.state)
- console.log("push");
- if (this.pushing || !updates.length) return
- this.pushing = true
- let version = getSyncedVersion(this.view.state)
- await pushUpdates(connection, version, updates)
- this.pushing = false
- console.log("push2");
-
- // Regardless of whether the push failed or new updates came in
- // while it was running, try again if there's updates remaining
- if (sendableUpdates(this.view.state).length)
- setTimeout(() => this.push(), 100)
- }
-
- async pull() {
- while (!this.done) {
- let version = getSyncedVersion(this.view.state)
- let updates = await pullUpdates(connection, version)
- console.log(updates)
- this.view.dispatch(receiveUpdates(this.view.state, updates))
- }
- }
-
- destroy() { this.done = true }
- })
- return [collab({startVersion}), plugin]
-}
-
-async function createPeer(connection: Connection) {
- let {version, doc} = await getDocument(connection)
- console.log(doc);
- let state = EditorState.create({
- doc,
- extensions: [basicSetup, peerExtension(version, connection)],
- })
- return new EditorView({state, parent: document.body})
-}
-
-//const client = new WebSocket('ws://127.0.0.1:3000/live/test');
-//client.addEventListener('open', () => createPeer(new Connection(client)));
\ No newline at end of file
diff --git a/src/app/components/editor/editor.component.ts b/src/app/components/editor/editor.component.ts
index 540a284..42f9550 100644
--- a/src/app/components/editor/editor.component.ts
+++ b/src/app/components/editor/editor.component.ts
@@ -1,6 +1,6 @@
-import { Component, ViewChild } from '@angular/core';
+import { Component,Input, ViewChild } from '@angular/core';
import { CodeExecutionService } from 'src/app/services/codeExecution.service';
-import { Compartment } from '@codemirror/state';
+import { Compartment,StateEffect } from '@codemirror/state';
import { CodeMirrorComponent } from '@sandkasten/codemirror6-editor';
import { LanguageDescription } from '@codemirror/language';
import { CODE_DEFAULTS, LANGUAGES } from '../languages';
@@ -36,6 +36,7 @@ import {
closeBracketsKeymap,
} from '@codemirror/autocomplete';
import { lintKeymap } from '@codemirror/lint';
+import {Connection, getDocument,peerExtension} from '../../services/connection.service'
const basicSetup: Extension = (() => [
highlightActiveLineGutter(),
@@ -131,6 +132,27 @@ export class EditorComponent {
this.languageCompartment.of(this.selectedLanguage.support!),
];
+ private client: WebSocket | undefined;
+ @Input()
+ set idRoom(idRoom: string) {
+ this.client = new WebSocket(`ws://127.0.0.1:3000/live/${idRoom}`);
+ this.client.addEventListener('open', async () => {
+ let conn = new Connection(this.client!);
+ let {version, doc} = await getDocument(conn);
+
+ this.codemirror.editor?.dispatch({
+ changes: {
+ from: 0,
+ to: this.codemirror.editor.state.doc.length,
+ insert: doc
+ }
+ })
+ this.codemirror.editor?.dispatch({
+ effects: StateEffect.appendConfig.of([peerExtension(version, conn)]),
+ })
+ });
+ }
+
constructor(private codeExecutionService: CodeExecutionService) {}
// Efface le contenu de l'éditeur
diff --git a/src/app/services/connection.service.ts b/src/app/services/connection.service.ts
new file mode 100644
index 0000000..ee29fee
--- /dev/null
+++ b/src/app/services/connection.service.ts
@@ -0,0 +1,104 @@
+import { ChangeSet, Text } from '@codemirror/state';
+import {EditorView} from "codemirror"
+import { Update, collab, getSyncedVersion, receiveUpdates, sendableUpdates } from '@codemirror/collab';
+import { ViewPlugin, ViewUpdate } from '@codemirror/view';
+
+export class Connection {
+ private requestId = 0;
+ private resolves: Record void> = {};
+
+ constructor(private client: WebSocket) {
+ client.addEventListener('message', (event) => {
+ const response = JSON.parse(event.data);
+ if ('_request' in response) {
+ const resolve = this.resolves[response._request];
+ if (resolve) {
+ resolve(response.payload);
+ } else {
+ console.error('Received response for unknown or already used request', response._request);
+ }
+ } else {
+ console.error('Received invalid response', response._request);
+ }
+ })
+ }
+
+ request(body: Record): Promise {
+ body['_request'] = this.requestId;
+ this.client.send(JSON.stringify(body));
+ return new Promise((resolve) => this.resolves[this.requestId++] = resolve);
+ }
+}
+
+function pushUpdates(
+ connection: Connection,
+ version: number,
+ fullUpdates: readonly Update[]
+): Promise {
+ // Strip off transaction data
+ let updates = fullUpdates.map(u => ({
+ clientID: u.clientID,
+ changes: u.changes.toJSON()
+ }));
+ return connection.request({type: "pushUpdates", version, updates});
+}
+
+function pullUpdates(
+ connection: Connection,
+ version: number
+): Promise {
+
+ return connection.request({type: "pullUpdates", version})
+ .then(updates => updates.map((u: any) => ({
+ changes: ChangeSet.fromJSON(u.changes),
+ clientID: u.clientID
+ })));
+}
+
+export function getDocument(
+ connection: Connection
+): Promise<{version: number, doc: Text}> {
+
+ return connection.request({ type: "getDocument" }).then(data => ({
+ version: data.version,
+ doc: Text.of(data.doc.split("\n"))
+ }));
+}
+
+export function peerExtension(startVersion: number, connection: Connection) {
+ let plugin = ViewPlugin.fromClass(class {
+ private pushing = false
+ private done = false
+
+ constructor(private view: EditorView) { this.pull() }
+
+ update(update: ViewUpdate) {
+ if (update.docChanged) this.push()
+ }
+
+ async push() {
+ let updates = sendableUpdates(this.view.state)
+
+ if (this.pushing || !updates.length) return
+ this.pushing = true
+ let version = getSyncedVersion(this.view.state)
+ await pushUpdates(connection, version, updates)
+ this.pushing = false
+ // Regardless of whether the push failed or new updates came in
+ // while it was running, try again if there's updates remaining
+ if (sendableUpdates(this.view.state).length)
+ setTimeout(() => this.push(), 100)
+ }
+
+ async pull() {
+ while (!this.done) {
+ let version = getSyncedVersion(this.view.state)
+ let updates = await pullUpdates(connection, version)
+ this.view.dispatch(receiveUpdates(this.view.state, updates))
+ }
+ }
+
+ destroy() { this.done = true }
+ })
+ return [collab({startVersion}), plugin]
+}
\ No newline at end of file