Update to CodeMirror 6 (#7)
continuous-integration/drone/push Build is passing Details

Update the editor to CodeMirror, using a [custom package](https://codefirst.iut.uca.fr/git/sandkasten/components/src/branch/main/projects/codemirror6-editor). All the Angular integration parts happen in this dedicated package, and the editor configuration is done here.

Language selection has been refactored to dynamically import on the fly the appropriate CodeMirror modes (now called extensions).

Co-authored-by: clfreville2 <clement.freville2@etu.uca.fr>
Reviewed-on: #7
Reviewed-by: Colin FRIZOT <colin.frizot@etu.uca.fr>
Reviewed-by: Bastien OLLIER <bastien.ollier@noreply.codefirst.iut.uca.fr>
Reviewed-by: Hugo PRADIER <hugo.pradier2@etu.uca.fr>
Reviewed-by: Matis MAZINGUE <matis.mazingue@etu.uca.fr>
error-extensions-editor
Clément FRÉVILLE 1 year ago
parent d41629abd0
commit af989fc165

225
package-lock.json generated

@ -17,12 +17,16 @@
"@angular/platform-browser": "^17.1.0", "@angular/platform-browser": "^17.1.0",
"@angular/platform-browser-dynamic": "^17.1.0", "@angular/platform-browser-dynamic": "^17.1.0",
"@angular/router": "^17.1.0", "@angular/router": "^17.1.0",
"@ctrl/ngx-codemirror": "^7.0.0", "@codemirror/lang-cpp": "^6.0.2",
"@codemirror/lang-javascript": "^6.2.1",
"@codemirror/state": "^6.4.0",
"@codemirror/view": "^6.23.0",
"@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",
"@sandkasten/codemirror6-editor": "^0.0.2",
"ansi-to-html": "^0.7.2", "ansi-to-html": "^0.7.2",
"codemirror": "^5.65.16", "codemirror": "^6.0.1",
"rxjs": "~7.8.1", "rxjs": "~7.8.1",
"sse.js": "^2.2.0", "sse.js": "^2.2.0",
"tslib": "^2.6.2", "tslib": "^2.6.2",
@ -2262,6 +2266,105 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@codemirror/autocomplete": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.12.0.tgz",
"integrity": "sha512-r4IjdYFthwbCQyvqnSlx0WBHRHi8nBvU+WjJxFUij81qsBfhNudf/XKKmmC2j3m0LaOYUQTf3qiEK1J8lO1sdg==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.17.0",
"@lezer/common": "^1.0.0"
},
"peerDependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"@lezer/common": "^1.0.0"
}
},
"node_modules/@codemirror/commands": {
"version": "6.3.3",
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.3.3.tgz",
"integrity": "sha512-dO4hcF0fGT9tu1Pj1D2PvGvxjeGkbC6RGcZw6Qs74TH+Ed1gw98jmUgd2axWvIZEqTeTuFrg1lEB1KV6cK9h1A==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.4.0",
"@codemirror/view": "^6.0.0",
"@lezer/common": "^1.1.0"
}
},
"node_modules/@codemirror/lang-cpp": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-cpp/-/lang-cpp-6.0.2.tgz",
"integrity": "sha512-6oYEYUKHvrnacXxWxYa6t4puTlbN3dgV662BDfSH8+MfjQjVmP697/KYTDOqpxgerkvoNm7q5wlFMBeX8ZMocg==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@lezer/cpp": "^1.0.0"
}
},
"node_modules/@codemirror/lang-javascript": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.1.tgz",
"integrity": "sha512-jlFOXTejVyiQCW3EQwvKH0m99bUYIw40oPmFjSX2VS78yzfe0HELZ+NEo9Yfo1MkGRpGlj3Gnu4rdxV1EnAs5A==",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.6.0",
"@codemirror/lint": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.17.0",
"@lezer/common": "^1.0.0",
"@lezer/javascript": "^1.0.0"
}
},
"node_modules/@codemirror/language": {
"version": "6.10.0",
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.0.tgz",
"integrity": "sha512-2vaNn9aPGCRFKWcHPFksctzJ8yS5p7YoaT+jHpc0UGKzNuAIx4qy6R5wiqbP+heEEdyaABA582mNqSHzSoYdmg==",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.23.0",
"@lezer/common": "^1.1.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0",
"style-mod": "^4.0.0"
}
},
"node_modules/@codemirror/lint": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.4.2.tgz",
"integrity": "sha512-wzRkluWb1ptPKdzlsrbwwjYCPLgzU6N88YBAmlZi8WFyuiEduSd05MnJYNogzyc8rPK7pj6m95ptUApc8sHKVA==",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"crelt": "^1.0.5"
}
},
"node_modules/@codemirror/search": {
"version": "6.5.5",
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.5.tgz",
"integrity": "sha512-PIEN3Ke1buPod2EHbJsoQwlbpkz30qGZKcnmH1eihq9+bPQx8gelauUwLYaY4vBOuBAuEhmpDLii4rj/uO0yMA==",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"crelt": "^1.0.5"
}
},
"node_modules/@codemirror/state": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.0.tgz",
"integrity": "sha512-hm8XshYj5Fo30Bb922QX9hXB/bxOAVH+qaqHBzw5TKa72vOeslyGwd4X8M0c1dJ9JqxlaMceOQ8RsL9tC7gU0A=="
},
"node_modules/@codemirror/view": {
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.23.0.tgz",
"integrity": "sha512-/51px9N4uW8NpuWkyUX+iam5+PM6io2fm+QmRnzwqBy5v/pwGg9T0kILFtYeum8hjuvENtgsGNKluOfqIICmeQ==",
"dependencies": {
"@codemirror/state": "^6.4.0",
"style-mod": "^4.1.0",
"w3c-keyname": "^2.2.4"
}
},
"node_modules/@colors/colors": { "node_modules/@colors/colors": {
"version": "1.5.0", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
@ -2271,20 +2374,6 @@
"node": ">=0.1.90" "node": ">=0.1.90"
} }
}, },
"node_modules/@ctrl/ngx-codemirror": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@ctrl/ngx-codemirror/-/ngx-codemirror-7.0.0.tgz",
"integrity": "sha512-qvIWtSTw/8fdXDnofBTX6LmTW9646HhawG2+Qyagf1vH40jCy0ZbHnkC20UYOVpUX+QCd1e/PQpkvWQ/1iGFzQ==",
"dependencies": {
"@types/codemirror": "^5.60.7",
"tslib": "^2.3.0"
},
"peerDependencies": {
"@angular/core": ">=16.0.0-0",
"@angular/forms": ">=16.0.0-0",
"codemirror": "^5.65.9"
}
},
"node_modules/@discoveryjs/json-ext": { "node_modules/@discoveryjs/json-ext": {
"version": "0.5.7", "version": "0.5.7",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
@ -2864,6 +2953,47 @@
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
"dev": true "dev": true
}, },
"node_modules/@lezer/common": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz",
"integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ=="
},
"node_modules/@lezer/cpp": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.1.2.tgz",
"integrity": "sha512-macwKtyeUO0EW86r3xWQCzOV9/CF8imJLpJlPv3sDY57cPGeUZ8gXWOWNlJr52TVByMV3PayFQCA5SHEERDmVQ==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/highlight": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.0.tgz",
"integrity": "sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==",
"dependencies": {
"@lezer/common": "^1.0.0"
}
},
"node_modules/@lezer/javascript": {
"version": "1.4.13",
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.13.tgz",
"integrity": "sha512-5IBr8LIO3xJdJH1e9aj/ZNLE4LSbdsx25wFmGRAZsj2zSmwAYjx26JyU/BYOCpRQlu1jcv1z3vy4NB9+UkfRow==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.1.3",
"@lezer/lr": "^1.3.0"
}
},
"node_modules/@lezer/lr": {
"version": "1.3.14",
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.14.tgz",
"integrity": "sha512-z5mY4LStlA3yL7aHT/rqgG614cfcvklS+8oFRFBYrs4YaWLJyKKM4+nN6KopToX0o9Hj6zmH6M5kinOYuy06ug==",
"dependencies": {
"@lezer/common": "^1.0.0"
}
},
"node_modules/@ljharb/through": { "node_modules/@ljharb/through": {
"version": "2.3.11", "version": "2.3.11",
"resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.11.tgz", "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.11.tgz",
@ -3323,6 +3453,20 @@
"win32" "win32"
] ]
}, },
"node_modules/@sandkasten/codemirror6-editor": {
"version": "0.0.2",
"resolved": "https://codefirst.iut.uca.fr/git/api/packages/sandkasten/npm/%40sandkasten%2Fcodemirror6-editor/-/0.0.2/codemirror6-editor-0.0.2.tgz",
"integrity": "sha512-hwqtIlIJFT1muFRqY66OC6qYtxj8XS0yG0SfDWh856CrZRcjSed5q4JBWROZqyPerc7L4PQiO3YmUnzR0YtCOA==",
"dependencies": {
"tslib": "^2.3.0"
},
"peerDependencies": {
"@angular/common": "^17.1.0",
"@angular/core": "^17.1.0",
"@codemirror/state": "^6.4.0",
"@codemirror/view": "^6.23.0"
}
},
"node_modules/@schematics/angular": { "node_modules/@schematics/angular": {
"version": "17.1.0", "version": "17.1.0",
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.1.0.tgz", "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.1.0.tgz",
@ -3482,14 +3626,6 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/codemirror": {
"version": "5.60.15",
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.15.tgz",
"integrity": "sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==",
"dependencies": {
"@types/tern": "*"
}
},
"node_modules/@types/connect": { "node_modules/@types/connect": {
"version": "3.4.38", "version": "3.4.38",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
@ -3547,7 +3683,8 @@
"node_modules/@types/estree": { "node_modules/@types/estree": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"dev": true
}, },
"node_modules/@types/express": { "node_modules/@types/express": {
"version": "4.17.21", "version": "4.17.21",
@ -3681,14 +3818,6 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/tern": {
"version": "0.23.9",
"resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz",
"integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==",
"dependencies": {
"@types/estree": "*"
}
},
"node_modules/@types/ws": { "node_modules/@types/ws": {
"version": "8.5.10", "version": "8.5.10",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz",
@ -4819,9 +4948,18 @@
} }
}, },
"node_modules/codemirror": { "node_modules/codemirror": {
"version": "5.65.16", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.16.tgz", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
"integrity": "sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==" "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/commands": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/lint": "^6.0.0",
"@codemirror/search": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0"
}
}, },
"node_modules/color-convert": { "node_modules/color-convert": {
"version": "1.9.3", "version": "1.9.3",
@ -5127,6 +5265,11 @@
"js-yaml": "bin/js-yaml.js" "js-yaml": "bin/js-yaml.js"
} }
}, },
"node_modules/crelt": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="
},
"node_modules/critters": { "node_modules/critters": {
"version": "0.0.20", "version": "0.0.20",
"resolved": "https://registry.npmjs.org/critters/-/critters-0.0.20.tgz", "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.20.tgz",
@ -10882,6 +11025,11 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/style-mod": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.0.tgz",
"integrity": "sha512-Ca5ib8HrFn+f+0n4N4ScTIA9iTOQ7MaGS1ylHcoVqW9J7w2w8PzN6g9gKmTYgGEBH8e120+RCmhpje6jC5uGWA=="
},
"node_modules/supports-color": { "node_modules/supports-color": {
"version": "5.5.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@ -11514,6 +11662,11 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/w3c-keyname": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="
},
"node_modules/watchpack": { "node_modules/watchpack": {
"version": "2.4.0", "version": "2.4.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",

@ -19,12 +19,16 @@
"@angular/platform-browser": "^17.1.0", "@angular/platform-browser": "^17.1.0",
"@angular/platform-browser-dynamic": "^17.1.0", "@angular/platform-browser-dynamic": "^17.1.0",
"@angular/router": "^17.1.0", "@angular/router": "^17.1.0",
"@ctrl/ngx-codemirror": "^7.0.0", "@codemirror/lang-cpp": "^6.0.2",
"@codemirror/lang-javascript": "^6.2.1",
"@codemirror/state": "^6.4.0",
"@codemirror/view": "^6.23.0",
"@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",
"@sandkasten/codemirror6-editor": "^0.0.2",
"ansi-to-html": "^0.7.2", "ansi-to-html": "^0.7.2",
"codemirror": "^5.65.16", "codemirror": "^6.0.1",
"rxjs": "~7.8.1", "rxjs": "~7.8.1",
"sse.js": "^2.2.0", "sse.js": "^2.2.0",
"tslib": "^2.6.2", "tslib": "^2.6.2",

@ -17,7 +17,7 @@ import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-poli
import { ReactiveFormsModule } from '@angular/forms'; import { ReactiveFormsModule } from '@angular/forms';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { CodemirrorModule } from '@ctrl/ngx-codemirror'; import { CodeMirrorComponent } from '@sandkasten/codemirror6-editor';
import { HttpClient, HttpClientModule } from '@angular/common/http'; import { HttpClient, HttpClientModule } from '@angular/common/http';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
@ -46,7 +46,6 @@ import { SafeHTMLPipe } from './safe-html.pipe';
AppRoutingModule, AppRoutingModule,
ReactiveFormsModule, ReactiveFormsModule,
FormsModule, FormsModule,
CodemirrorModule,
// Injection des HttpClient pour notre module de traduction // Injection des HttpClient pour notre module de traduction
HttpClientModule, HttpClientModule,
// Initialisation du module de traduction // Initialisation du module de traduction
@ -60,7 +59,8 @@ import { SafeHTMLPipe } from './safe-html.pipe';
deps: [HttpClient] deps: [HttpClient]
}, },
defaultLanguage: 'fr' defaultLanguage: 'fr'
}) }),
CodeMirrorComponent
], ],
providers: [TranslationService], providers: [TranslationService],
bootstrap: [AppComponent] bootstrap: [AppComponent]

@ -1,35 +1,19 @@
<div> <div>
<div> <div>
<ngx-codemirror <codemirror6-editor
[options]="{
theme: 'material',
lineNumbers: true,
lineWrapping: true,
mode: mode,
autofocus: true
}"
[(ngModel)]="editorContent" [(ngModel)]="editorContent"
[autoFocus]="true" [extensions]="extensions"
> ></codemirror6-editor>
</ngx-codemirror>
</div> </div>
<pre [innerHTML]="resultContent | safeHTML"></pre> <pre [innerHTML]="resultContent | safeHTML"></pre>
<div> <div>
<label for="language">Langage de programmation</label> <label for="language">Langage de programmation</label>
<select <select id="language" [(ngModel)]="selectedLanguage">
id="language" @for (language of languages; track language.name) {
name="language" <option [ngValue]="language">{{ language.name }}</option>
[(ngModel)]="mode" }
(ngModelChange)="changeMode()">
<option value="text/typescript" selected>TypeScript</option>
<option value="text/javascript">JavaScript</option>
<option value="text/x-csrc">C</option>
<option value="text/x-c++src">C++</option>
<option value="text/x-sh">Shell</option>
</select> </select>
</div> </div>
@ -38,10 +22,6 @@
</div> </div>
<button (click)="onRunButtonClicked()" [disabled]="isLoaded">Lancer</button> <button (click)="onRunButtonClicked()" [disabled]="isLoaded">Lancer</button>
<div *ngIf="!isLoaded">
<p>Chargement: {{ loadingProgress }}%</p>
<div class="loading-bar" [style.width.%]="loadingProgress"></div>
</div>
<div> <div>
<label for="fileInput">Charger à partir d'un fichier</label> <label for="fileInput">Charger à partir d'un fichier</label>

@ -1,96 +1,55 @@
import { Component, OnInit } from "@angular/core"; import { Component, ViewChild } from '@angular/core';
import { Router } from "@angular/router"; import { CodeExecutionService } from 'src/app/services/codeExecution.service';
import { CodeExecutionService } from "src/app/services/codeExecution.service"; import { basicSetup } from 'codemirror';
import "codemirror/mode/shell/shell.js"; import { Compartment, Extension } from '@codemirror/state';
import "codemirror/mode/clike/clike.js"; import { CodeMirrorComponent } from '@sandkasten/codemirror6-editor';
import Convert from 'ansi-to-html'; import { LanguageDescription } from '@codemirror/language';
import { CODE_DEFAULTS, LANGUAGES } from '../languages';
// Exemple de code pour chaque langage autorisé
const codeDefaults = {
"text/typescript": `const component = {
name: "@exemple/Typescript",
author: "Sandkasten",
repo: "https://codefirst.iut.uca.fr/git/sandkasten/sandkasten-web.git"
};
const hello: string = 'Bonjour ceci est un test de code en typescript';`,
"text/javascript": `const component = {
name: "@exemple/Javascript",
author: "Sandkasten",
repo: "https://codefirst.iut.uca.fr/git/sandkasten/sandkasten-web.git"
};
const hello = 'Bonjour ceci est un test de code en javascript';`,
"text/x-c++src": `#include <iostream>
using namespace std;
int main() {
cout << "Bonjour ceci est un test de code en c++" << endl;
return 0;
}`,
"text/x-csrc": `#include <stdio.h>
int main() {
printf("Bonjour ceci est un test de code en c");
return 0;
}`,
"text/x-sh": `#!/bin/bash
echo "Bonjour ceci est un test de code en shell"`,
};
// Langages autorisés
type AllowedLanguage = keyof typeof codeDefaults;
@Component({ @Component({
selector: "app-editor", selector: "app-editor",
templateUrl: "./editor.component.html", templateUrl: "./editor.component.html",
styleUrls: ["./editor.component.scss"], styleUrls: ["./editor.component.scss"],
}) })
export class EditorComponent implements OnInit { export class EditorComponent {
loadingProgress: number = 0; // Pour suivre la progression du chargement
isLoaded: boolean = false; // Pour vérifier si le chargement est terminé isLoaded: boolean = false; // Pour vérifier si le chargement est terminé
readonly languages: LanguageDescription[] = LANGUAGES;
// Mode par défaut // Mode par défaut
mode: AllowedLanguage = "text/typescript"; private _selectedLanguage = this.languages.find((lang) => lang.name === "JavaScript")!;
options = { get selectedLanguage(): LanguageDescription {
lineNumbers: true, return this._selectedLanguage;
mode: this.mode, }
}; set selectedLanguage(value: LanguageDescription) {
defaults = codeDefaults; 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)
});
});
}
// Contenu de l'éditeur que l'on passera au serveur // Contenu de l'éditeur que l'on passera au serveur
editorContent: string = this.defaults[this.mode as keyof typeof codeDefaults]; editorContent: string = CODE_DEFAULTS[this.selectedLanguage.name as keyof typeof CODE_DEFAULTS];
resultContent: string = ""; resultContent: string = "";
// Message d'erreur // Message d'erreur
errorMessage: string = ""; errorMessage: string = "";
constructor( @ViewChild(CodeMirrorComponent) private codemirror!: CodeMirrorComponent;
private router: Router,
private codeExecutionService: CodeExecutionService
) {}
ngOnInit(): void {
// Appel à changeMode pour mettre à jour le contenu de l'éditeur et le mode
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 private readonly languageCompartment = new Compartment();
changeMode(): void { protected readonly extensions: Extension[] = [
this.options = { basicSetup,
...this.options, this.languageCompartment.of(this.selectedLanguage.support!)
mode: this.mode, ];
};
this.editorContent = this.defaults[this.mode as keyof typeof codeDefaults];
}
// Affiche le contenu de l'éditeur constructor(
handleChange($event: Event): void { private codeExecutionService: CodeExecutionService
console.log("ngModelChange", $event); ) {
} }
// Efface le contenu de l'éditeur // Efface le contenu de l'éditeur
@ -98,77 +57,34 @@ export class EditorComponent implements OnInit {
this.editorContent = ""; this.editorContent = "";
} }
loadFromFile(event: any): void { onRunButtonClicked() {
const file = event.target.files[0]; // Le code à exécuter est le contenu de l'éditeur
if (file) { const codeToExecute = this.editorContent;
const allowedExtensions = ["sh", "js", "ts", "cpp", "c"];
const extension = file.name.split(".").pop()?.toLowerCase();
if (extension && allowedExtensions.includes(extension)) {
// Identifiez le mode en fonction de l'extension
const modeMap: Record<string, AllowedLanguage> = {
sh: "text/x-sh",
js: "text/javascript",
ts: "text/typescript",
cpp: "text/x-c++src",
c: "text/x-csrc",
};
this.mode = modeMap[extension];
// Mettez à jour le contenu de l'éditeur et le mode this.codeExecutionService.executeCode(codeToExecute, this.selectedLanguage.name);
this.changeMode();
const reader = new FileReader(); this.resultContent = '';
reader.onload = (e) => {
this.editorContent = e.target?.result as string;
this.errorMessage = ""; // Réinitialisez le message d'erreur en cas de succès.
};
reader.readAsText(file);
} else {
this.errorMessage =
"Unsupported file type. Please select a file with one of the following extensions: sh, js, ts, cpp, c";
console.error(this.errorMessage);
}
}
} }
saveToFile(): void { loadFromFile(event: Event) {
const languageExtensionMap: Record<AllowedLanguage, string> = { const file = (event.target as HTMLInputElement).files![0];
"text/x-sh": "sh", for (const language of this.languages) {
"text/javascript": "js", if (language.extensions.some(ext => file.name.endsWith(`.${ext}`))) {
"text/typescript": "ts", this.selectedLanguage = language;
"text/x-c++src": "cpp", return;
"text/x-csrc": "c",
};
if (languageExtensionMap[this.mode]) {
const extension = languageExtensionMap[this.mode];
if (this.editorContent.trim() === "") {
this.errorMessage = "Cannot save an empty file.";
console.error(this.errorMessage);
} else {
this.errorMessage = ""; // Réinitialisez le message d'erreur en cas de succès.
const blob = new Blob([this.editorContent], { type: "text/plain" });
const a = document.createElement("a");
a.href = window.URL.createObjectURL(blob);
a.download = `code.${extension}`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
} }
} else {
this.errorMessage =
"Unsupported language. Please select one of the following languages: shell, javascript, typescript, c++, c";
console.error(this.errorMessage);
} }
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);
} }
onRunButtonClicked() { saveToFile() {
// Le code à exécuter est le contenu de l'éditeur const blob = new Blob([this.editorContent], { type: 'text/plain' });
const codeToExecute = this.editorContent; const a = document.createElement('a');
a.download = `code.${this.selectedLanguage.extensions![0]}`;
this.codeExecutionService.executeCode(codeToExecute, this.mode); a.href = URL.createObjectURL(blob);
a.click();
this.resultContent = '';
} }
} }

@ -0,0 +1,49 @@
import {LanguageDescription} from "@codemirror/language";
import {javascript} from "@codemirror/lang-javascript";
export const CODE_DEFAULTS = {
'C': /** @lang C */ `#include <stdio.h>
int main() {
printf("Hello, World!\\n");
return 0;
}`,
'C++': /** @lang C++ */ `#include <iostream>
int main() {
std::cout << "Hello, World!\\n";
return 0;
}`,
'JavaScript': /** @lang JS */ `console.log("Hello, World!");`,
'TypeScript': /** @lang TS */ `console.log("Hello, World!");`
};
export const LANGUAGES = [
LanguageDescription.of({
name: 'C',
extensions: ['c', 'h', 'ino'],
load() {
return import("@codemirror/lang-cpp").then(m => m.cpp())
}
}),
LanguageDescription.of({
name: "C++",
alias: ['cpp'],
extensions: ['cpp', "c++", 'cc', 'cxx', 'hpp', "h++", 'hh', 'hxx'],
load() {
return import("@codemirror/lang-cpp").then(m => m.cpp())
}
}),
LanguageDescription.of({
name: 'JavaScript',
alias: ['ecmascript', 'js', 'node'],
extensions: ['js', 'mjs', 'cjs'],
support: javascript(),
}),
LanguageDescription.of({
name: 'TypeScript',
alias: ['ts'],
extensions: ['ts'],
load() {
return import("@codemirror/lang-javascript").then(m => m.javascript({typescript: true}))
}
}),
];

@ -1,6 +1,3 @@
import 'codemirror/mode/javascript/javascript';
import 'codemirror/mode/markdown/markdown';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module'; import { AppModule } from './app/app.module';

@ -1,6 +1,3 @@
@import 'codemirror/lib/codemirror.css';
@import 'codemirror/theme/material.css';
//region Colors //region Colors
$color-purple: #605FFC; $color-purple: #605FFC;
$color-white: #FFFFFF; $color-white: #FFFFFF;

Loading…
Cancel
Save