src/app/ide/ide.component.ts
selector | app-ide |
styleUrls | ./ide.component.scss |
templateUrl | ./ide.component.html |
Properties |
Methods |
constructor(route: ActivatedRoute, runCodeService: RunCodeService, fileService: FileService, apiService: ApiService, router: Router)
|
||||||||||||||||||
Defined in src/app/ide/ide.component.ts:37
|
||||||||||||||||||
Parameters :
|
ngOnInit |
ngOnInit()
|
Defined in src/app/ide/ide.component.ts:43
|
Returns :
void
|
optimizeURI | ||||||
optimizeURI(uri: string)
|
||||||
Defined in src/app/ide/ide.component.ts:186
|
||||||
Parameters :
Returns :
string
|
runFile |
runFile()
|
Defined in src/app/ide/ide.component.ts:150
|
Returns :
void
|
updateFile |
updateFile()
|
Defined in src/app/ide/ide.component.ts:130
|
Returns :
void
|
updateInput | ||||||
updateInput(val: string)
|
||||||
Defined in src/app/ide/ide.component.ts:126
|
||||||
Parameters :
Returns :
void
|
extensions |
Type : []
|
Default value : ['.cpp', '.py', '.java']
|
Defined in src/app/ide/ide.component.ts:21
|
file |
Type : File
|
Default value : {
filename: 'Untitled',
language: '.cpp',
text: '',
username: JSON.parse(this.apiService.getToken()).username,
path: '/'
}
|
Defined in src/app/ide/ide.component.ts:28
|
inp |
Type : string
|
Default value : ''
|
Defined in src/app/ide/ide.component.ts:20
|
inputField |
Decorators :
@ViewChild(InputComponent)
|
Defined in src/app/ide/ide.component.ts:35
|
isCompiling |
Default value : false
|
Defined in src/app/ide/ide.component.ts:25
|
isError |
Default value : false
|
Defined in src/app/ide/ide.component.ts:26
|
isSaved |
Default value : false
|
Defined in src/app/ide/ide.component.ts:23
|
isUploading |
Default value : false
|
Defined in src/app/ide/ide.component.ts:24
|
isUpToDate |
Default value : false
|
Defined in src/app/ide/ide.component.ts:27
|
loadingFile |
Default value : false
|
Defined in src/app/ide/ide.component.ts:22
|
Public route |
Type : ActivatedRoute
|
Defined in src/app/ide/ide.component.ts:39
|
Public runCodeService |
Type : RunCodeService
|
Defined in src/app/ide/ide.component.ts:39
|
runField |
Decorators :
@ViewChild(IdeCompileComponent)
|
Defined in src/app/ide/ide.component.ts:36
|
saveField |
Decorators :
@ViewChild(SaveFileComponent)
|
Defined in src/app/ide/ide.component.ts:37
|
import {Component, OnInit, ViewChild} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
import {InputComponent} from '../input/input.component';
import {IdeCompileComponent} from '../ide-compile/ide-compile.component';
import {RunCodeService} from '../run-code.service';
import {SaveFileComponent} from '../save-file/save-file.component';
import {File} from '../file';
import {FileService} from '../file.service';
import {ApiService} from '../api.service';
declare const CodeMirror: any;
@Component({
selector: 'app-ide',
templateUrl: './ide.component.html',
styleUrls: ['./ide.component.scss']
})
export class IdeComponent implements OnInit {
inp = '';
extensions = ['.cpp', '.py', '.java'];
loadingFile = false;
isSaved = false;
isUploading = false;
isCompiling = false;
isError = false;
isUpToDate = false;
file: File = {
filename: 'Untitled',
language: '.cpp',
text: '',
username: JSON.parse(this.apiService.getToken()).username,
path: '/'
};
@ViewChild(InputComponent) inputField;
@ViewChild(IdeCompileComponent) runField;
@ViewChild(SaveFileComponent) saveField;
constructor(public route: ActivatedRoute, public runCodeService: RunCodeService, private fileService: FileService,
private apiService: ApiService, private router: Router) {
}
ngOnInit(): void {
const filepath = decodeURIComponent(this.route.snapshot.params.filepath);
const editorArea = document.getElementById('editor');
const editor = CodeMirror.fromTextArea(editorArea as HTMLTextAreaElement, {
lineNumbers: true,
theme: 'material-ocean',
mode: 'text/x-c++src',
autoCloseBrackets: true,
matchBrackets: true
});
editor.setSize('auto', '70vh');
Object.assign((document.getElementsByClassName('CodeMirror')[0] as HTMLTextAreaElement).style, {
borderBottom: '1px solid #ddf',
padding: '20px',
fontFamily: '"Anonymous Pro", monospace',
});
let activeLang = 0;
const langs = ['C++', 'Python', 'Java'];
const langsMime = ['text/x-c++src', 'text/x-python', 'text/x-java'];
const code = [`#include <iostream>
using namespace std;
int main() {
cout << "Hello World!\\n";
return 0;
}`, `print("Hello World!")`, `class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}`];
editor.setValue(code[activeLang]);
this.file.text = code[activeLang];
const tl = document.getElementById('toggle-lang') as HTMLDivElement;
tl.onclick = () => {
if (this.isSaved) {
return;
}
activeLang = (activeLang + 1) % 3;
this.file.language = this.extensions[activeLang];
tl.innerHTML = langs[activeLang];
editor.setValue(code[activeLang]);
editor.setOption('mode', langsMime[activeLang]);
};
editor.on('update', () => {
if (!this.isUploading) {
this.isUpToDate = false;
document.getElementById('saveBtn').innerHTML = 'Save File';
}
code[activeLang] = editor.getValue();
this.file.text = editor.getValue();
});
if (filepath !== 'new') {
const arr = filepath.split('.');
if (!(['cpp', 'py', 'java']).includes(arr[arr.length - 1])) {
this.router.navigate(['arena/file/new']).then(() => window.location.reload());
}
const arrf = filepath.split('/');
const arrg = arrf.pop().split('.');
arrg.pop();
this.file.filename = arrg.join('.');
this.file.path = arrf.join('/');
this.file.language = '.' + arr[arr.length - 1];
tl.innerHTML = langs[this.extensions.indexOf(this.file.language)];
this.fileService.getFileContent(this.file.username, filepath)
.subscribe(data => {
editor.setValue(data);
this.isSaved = true;
this.isUpToDate = true;
this.loadingFile = false;
console.log(this.file);
}, error => {
this.router.navigate(['arena/file/new']).then(() => window.location.reload());
});
} else {
this.loadingFile = false;
}
}
updateInput(val: string): void {
this.inp = val;
}
updateFile(): void {
const btn = document.getElementById('saveBtn') as HTMLButtonElement;
if (btn.classList.contains('disabled')) {
return;
}
this.isUploading = true;
btn.innerHTML = 'Saving...';
this.fileService.upload(this.file, false)
.subscribe(data => {
btn.innerHTML = 'Saved';
this.isUploading = false;
this.isUpToDate = true;
console.log(data);
}, error => {
console.log(error);
this.isUploading = false;
btn.innerHTML = 'Save File';
});
}
runFile(): void {
const btn = document.getElementById('runBtn');
if (btn.classList.contains('disabled')) {
return;
}
this.isCompiling = true;
this.runCodeService.compileFile(this.file)
.subscribe(data => {
this.runCodeService.executeFile(this.file, this.inp)
.subscribe(d => {
console.log(d);
this.runField.status = '<div class="code">' + d + '</div>';
this.runField.setState(true);
this.isCompiling = false;
}, err => {
console.log(err);
this.isCompiling = false;
this.isError = true;
this.runField.status = '<div class="error">Runtime Error!</div>';
this.runField.setState(true);
setTimeout(() => {
this.isError = false;
}, 3000);
});
}, error => {
console.log(error);
this.isCompiling = false;
this.isError = true;
this.runField.status = '<div class="error">Compilation Error!</div>';
this.runField.setState(true);
setTimeout(() => {
this.isError = false;
}, 3000);
});
}
optimizeURI(uri: string): string {
const ret: string[] = [];
for (const c of uri.split('/')) {
if (c === '' || c === '.') {
} else if (c === '..') {
ret.pop();
} else {
ret.push(c);
}
}
return ret.join('') === '' ? '/' : '/' + ret.join('/') + '/';
}
}
<div id="ide-cover" *ngIf="loadingFile">
<div id="ide-cover-text">
Loading file...
</div>
</div>
<div class="container">
<div id="toggle-lang" [class.disabled]="isSaved">C++</div>
<div id="attempt">
<span *ngIf="!isUpToDate">• </span>
<span id="ideFileName">{{optimizeURI(file.path)}}{{file.filename + file.language}}</span>
<button (click)="inputField.setState(true);" id="inputBtn">Input</button>
<button (click)="runFile()" id="runBtn" [class.disabled]="isCompiling || isError">{{isError ? 'Error' : (isCompiling ? 'Compiling...' : 'Run File')}}</button>
<button (click)="!isSaved ? this.saveField.setState(true) : updateFile();"
[class.disabled]="isUploading || isUpToDate"
id="saveBtn">{{isUploading ? "Saving File..." : "Save File"}}</button>
</div>
<label for="editor"></label>
<textarea id="editor" name="editor" value="{{inp}}"></textarea>
</div>
<app-input (valueEmit)="updateInput($event)"></app-input>
<app-ide-compile [statusVal]="runCodeService.runStatus"></app-ide-compile>
<app-save-file (savedFile)="isSaved = isUpToDate = true;" [file]="file"></app-save-file>
./ide.component.scss
.container {
position: relative;
padding: 20px;
#toggle-lang {
position: absolute;
background: var(--bgcolor);
color: var(--color);
padding: 5px 10px;
right: 22px;
top: 22px;
z-index: 100;
cursor: pointer;
user-select: none;
&.disabled {
cursor: not-allowed;
}
}
label {
display: none;
}
#attempt {
position: absolute;
right: 24px;
bottom: 24px;
z-index: 100;
#runBtn,
#inputBtn,
#saveBtn {
display: inline-block;
background: transparent;
color: #ddf;
margin: 2px;
cursor: pointer;
transition: 0.25s all;
user-select: none;
&:hover {
background: var(--color);
color: var(--bgcolor);
}
&.disabled:hover {
cursor: default;
background: transparent;
color: #ddf;
}
}
}
}
#ideFileName {
margin-right: 10px;
}
#ide-cover {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #002e;
color: #ddf;
font-size: 1.5em;
z-index: 10000;
#ide-cover-text {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%);
}
}
@media screen and (max-width: 800px) {
.container {
padding: 20px 0;
}
#attempt {
right: 4px !important;
bottom: 24px !important;
}
#toggle-lang {
right: 0 !important;
}
}