Commit 13bf44f2 authored by Adarsh's avatar Adarsh

Merge remote-tracking branch 'refs/remotes/origin/master'

necessary
parents 736c62dd feaef67b
...@@ -10,13 +10,13 @@ This is the default script to connect with the MySQL server in the backend. The ...@@ -10,13 +10,13 @@ This is the default script to connect with the MySQL server in the backend. The
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept"); header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
header("Content-Type: application/json; charset=UTF-8"); header("Content-Type: application/json; charset=UTF-8");
$db_host = 'localhost'; // Uncomment and assign values according to your system $db_host = 'localhost';
$db_username = 'root'; $db_username = 'root';
$db_password = ''; $db_password = '';
$db_name = 'ssl_database'; // add name of your own databse from mysql phpmyadmin $db_name = 'ssl_database';
$mysqli = new mysqli($db_host, $db_username, $db_password,$db_name); $mysqli = new mysqli($db_host, $db_username, $db_password,$db_name);
if ($mysqli->connect_error) { if ($mysqli->connect_error) {
die('Error : ('. $mysqli->connect_errno .') '. $mysqli->connect_error); die('Error : ('. $mysqli->connect_errno .') '. $mysqli->connect_error);
} }
?> ?>
\ No newline at end of file
...@@ -4,6 +4,12 @@ ...@@ -4,6 +4,12 @@
This script deletes a given code file, or a directory in the user's workspace, given its path. This script deletes a given code file, or a directory in the user's workspace, given its path.
*/ */
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Credentials: true');
header("Access-Control-Allow-Methods: PUT, GET, POST, DELETE");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
header("Content-Type: application/json; charset=UTF-8");
include_once("database.php"); include_once("database.php");
$postData = file_get_contents("php://input"); $postData = file_get_contents("php://input");
...@@ -21,7 +27,7 @@ if (isset($postData) && !empty($postData)) { ...@@ -21,7 +27,7 @@ if (isset($postData) && !empty($postData)) {
if(strcmp($lang, '.java') == 0) if(strcmp($lang, '.java') == 0)
{ {
$exec_path = $exec_path . $lang; $exec_path = $exec_path . '.class';
} }
if (unlink($path)) { if (unlink($path)) {
...@@ -41,7 +47,7 @@ if (isset($postData) && !empty($postData)) { ...@@ -41,7 +47,7 @@ if (isset($postData) && !empty($postData)) {
$path = '../users/' . $username . '/' . trim($request['file']['path']) . '/' . $dirname; $path = '../users/' . $username . '/' . trim($request['file']['path']) . '/' . $dirname;
$exec_path = '../user_execs/' . $username . '/' . trim($request['file']['path']) . '/' . $dirname; $exec_path = '../user_execs/' . $username . '/' . trim($request['file']['path']) . '/' . $dirname;
$ret_stat = 0; $ret_stat = 0;
system('rm -r ' . $path, $ret_stat); system('rm -r ' . $path, $ret_stat);
system('rm -r ' . $exec_path); system('rm -r ' . $exec_path);
......
...@@ -4,6 +4,12 @@ ...@@ -4,6 +4,12 @@
This script saves a given code file for a user, given it's path. This script saves a given code file for a user, given it's path.
*/ */
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Credentials: true');
header("Access-Control-Allow-Methods: PUT, GET, POST, DELETE");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
header("Content-Type: application/json; charset=UTF-8");
include_once("database.php"); include_once("database.php");
$postData = file_get_contents("php://input"); $postData = file_get_contents("php://input");
......
<?php <?php
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Credentials: true');
header("Access-Control-Allow-Methods: PUT, GET, POST, DELETE");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
header("Content-Type: application/json; charset=UTF-8");
$postData = file_get_contents("php://input"); $postData = file_get_contents("php://input");
if(isset($postData) && !empty($postData)) { if(isset($postData) && !empty($postData)) {
$request = json_decode($postData, true); $request = json_decode($postData, true);
$username = $request['username']; $username = $request['username'];
$dirname = $request['dir_name']; $dirname = $request['dirname'];
$path = "../users/" . $username . "/" . $request['curr_dir'] . "/" . $dirname; $path = "../users/" . $username . "/" . $request['path'] . "/" . $dirname;
if(file_exists($path)) { if(file_exists($path)) {
$msg = "directory already exists"; $msg = "directory already exists";
...@@ -19,4 +26,4 @@ if(isset($postData) && !empty($postData)) { ...@@ -19,4 +26,4 @@ if(isset($postData) && !empty($postData)) {
} }
} }
?> ?>
\ No newline at end of file
...@@ -4,7 +4,15 @@ ...@@ -4,7 +4,15 @@
* This script registers a user using a username, password, name, and email (provided through POST). This script communicates with the MySQL server to save user data. * This script registers a user using a username, password, name, and email (provided through POST). This script communicates with the MySQL server to save user data.
*/ */
<<<<<<< HEAD
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Credentials: true');
header("Access-Control-Allow-Methods: PUT, GET, POST, DELETE");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
header("Content-Type: application/json; charset=UTF-8");
=======
>>>>>>> 8601987f1aa6573181cb9427847fcf57dc1afcf6
include_once("database.php"); include_once("database.php");
...@@ -47,4 +55,4 @@ if (isset($postData) && !empty($postData)) { ...@@ -47,4 +55,4 @@ if (isset($postData) && !empty($postData)) {
echo "mysqli_error($mysqli)"; echo "mysqli_error($mysqli)";
} }
} }
?> ?>
\ No newline at end of file
...@@ -13,8 +13,7 @@ const routes: Routes = [ ...@@ -13,8 +13,7 @@ const routes: Routes = [
{path: 'home', component: HomeComponent, canActivate: [AuthGuard]}, {path: 'home', component: HomeComponent, canActivate: [AuthGuard]},
{path: 'arena/question/:title', component: ArenaComponent, canActivate: [AuthGuard]}, {path: 'arena/question/:title', component: ArenaComponent, canActivate: [AuthGuard]},
{path: 'arena/problem/:id', component: ArenaComponent, canActivate: [AuthGuard]}, {path: 'arena/problem/:id', component: ArenaComponent, canActivate: [AuthGuard]},
{path: 'arena/file/:id', component: IdeComponent, canActivate: [AuthGuard]}, {path: 'arena/file/:filepath', component: IdeComponent, canActivate: [AuthGuard]},
{path: 'arena/file/new', component: IdeComponent, canActivate: [AuthGuard]},
{path: 'user', component: UserComponent, canActivate: [AuthGuard]}, {path: 'user', component: UserComponent, canActivate: [AuthGuard]},
{path: 'files', component: FileComponent, canActivate: [AuthGuard]}, {path: 'files', component: FileComponent, canActivate: [AuthGuard]},
{path: 'login', component: LoginComponent}, {path: 'login', component: LoginComponent},
...@@ -30,7 +29,7 @@ const routes: Routes = [ ...@@ -30,7 +29,7 @@ const routes: Routes = [
export class AppRoutingModule { export class AppRoutingModule {
} }
export var routerComponents = [ export const routerComponents = [
HomeComponent, HomeComponent,
ArenaComponent, ArenaComponent,
UserComponent, UserComponent,
......
...@@ -24,7 +24,7 @@ export class ArenaComponent implements OnInit { ...@@ -24,7 +24,7 @@ export class ArenaComponent implements OnInit {
question: Question; question: Question;
code: string[] = [`#include <iostream> code: string[] = [`#include <iostream>
using namespace std; using namespace std;
int main() { int main() {
cout << "Hello World!\\n"; cout << "Hello World!\\n";
return 0; return 0;
...@@ -47,7 +47,7 @@ export class ArenaComponent implements OnInit { ...@@ -47,7 +47,7 @@ export class ArenaComponent implements OnInit {
} }
ngOnInit(): void { ngOnInit(): void {
this.title = this.router.url.split('/')[3]; this.title = this.router.url.split('/')[3];
this.getQuestion(); this.getQuestion();
...@@ -75,7 +75,7 @@ export class ArenaComponent implements OnInit { ...@@ -75,7 +75,7 @@ export class ArenaComponent implements OnInit {
const code: string[] = [`#include <iostream> const code: string[] = [`#include <iostream>
using namespace std; using namespace std;
int main() { int main() {
cout << "Hello World!\\n"; cout << "Hello World!\\n";
return 0; return 0;
......
<div class="card" [style.marginLeft]="level * 20 + 'px'" [style.background]="isFile ? '#002' : '#022'"> <div [style.background]="isFile ? '#002' : '#022'" [style.marginLeft]="level * 20 + 'px'" class="card">
<div class="title" *ngIf="isFile">{{file.filename}}{{file.language}}</div> <div *ngIf="!isNew && isFile" class="title">{{file.filename}}{{file.language}}</div>
<div class="title" *ngIf="!isFile">{{directory.name}}</div> <div *ngIf="!isNew && !isFile" class="title">{{directory.name}}</div>
<div class="dir-desc" *ngIf="!isFile">{{directory.dirs.length}} directories, {{directory.files.length}} files</div> <div *ngIf="!isNew && !isFile" class="dir-desc">{{directory.dirs.length}} directories, {{directory.files.length}}
<div *ngIf="isFile"></div> files
<div class="file-buttons"> </div>
<button (click)="onDelete()" [disabled]="deleting" [class.disabled]="deleting">Delete</button>
<button *ngIf="!isFile" (click)="isExpanded = !isExpanded">{{isExpanded ? 'Collapse' : 'Expand'}}</button> <div *ngIf="isNew" class="title">
<button *ngIf="isFile">Edit</button> <input (input)="isErrorCreating = false" [(ngModel)]="newName" [disabled]="creating" id="newFilenameInput"
[placeholder]="'Name of new ' + (isFile ? 'file' : 'directory')" type="text">
<label for="newFilenameInput" *ngIf="isFile" (click)="lang = (lang + 1) % 3">{{extensions[lang]}}</label>
</div>
<div *ngIf="isNew || isFile"></div>
<div *ngIf="!isNew" class="file-buttons">
<button (click)="onDelete()" [class.disabled]="deleting || isErrorDeleting"
[disabled]="deleting || isErrorDeleting">{{isErrorDeleting ? 'Error' : (deleting ? 'Deleting...' : 'Delete')}}</button>
<button (click)="isExpanded = !isExpanded" *ngIf="!isFile">{{isExpanded ? 'Collapse' : 'Expand'}}</button>
<button (click)="isExpanded = true; creatingNewSub = 1" *ngIf="!isFile">New Directory</button>
<button (click)="isExpanded = true; creatingNewSub = 2" *ngIf="!isFile">New File</button>
<button *ngIf="isFile" [routerLink]="getRouterLink()">Edit</button>
<button *ngIf="isFile">Run</button> <button *ngIf="isFile">Run</button>
</div> </div>
<div *ngIf="isNew" class="file-buttons">
<button (click)="cancelled.emit(true)" [class.disabled]="creating" [disabled]="creating">Cancel</button>
<button (click)="isFile ? onCreateFile() : onCreateDir()"
[class.disabled]="newName==='' || creating || isErrorCreating"
[disabled]="newName==='' || creating || isErrorCreating">{{isErrorCreating ? 'Error' : (creating ? 'Creating...' : 'Create')}}</button>
</div>
</div> </div>
<div class="subs" *ngIf="!isFile" [style.display]="isExpanded ? 'block' : 'none'">
<app-file-dir-card *ngFor="let dir of directory.dirs" [isFile]="false" [directory]="dir" [level]="level + 1" [trace]="addToTraceDir(dir)" (deleteFile)="deleteFileExec($event)" (deleteDir)="deleteDirExec($event)"></app-file-dir-card> <div *ngIf="!isNew && !isFile" [style.display]="isExpanded ? 'block' : 'none'" class="subs">
<app-file-dir-card *ngFor="let file of directory.files" [isFile]="true" [file]="file" [level]="level + 1" [trace]="addToTraceFile(file)" (deleteFile)="deleteFileExec($event)" (deleteDir)="deleteDirExec($event)"></app-file-dir-card>
<app-file-dir-card (cancelled)="creatingNewSub = 0" (createDir)="createDirExec($event)" (createFile)="createFileExec($event)"
*ngIf="creatingNewSub !== 0" [isFile]="creatingNewSub === 2" [level]="level + 1"
[isNew]="true" [parentPath]="directory.path + directory.name + '/'"></app-file-dir-card>
<app-file-dir-card (deleteDir)="deleteDirExec($event)" (deleteFile)="deleteFileExec($event)"
*ngFor="let dir of directory.dirs" [directory]="dir"
[isFile]="false" [isNew]="false" [level]="level + 1"
[trace]="addToTraceDir(dir)"></app-file-dir-card>
<app-file-dir-card (deleteDir)="deleteDirExec($event)" (deleteFile)="deleteFileExec($event)"
*ngFor="let file of directory.files" [file]="file"
[isFile]="true" [isNew]="false" [level]="level + 1"
[trace]="addToTraceFile(file)"></app-file-dir-card>
</div> </div>
.card { .card {
display: grid; display: grid;
grid-template-columns: 33.33% 33.33% 33.33%; grid-template-columns: 30% 20% 50%;
height: 3em; height: 3em;
border-bottom: 1px solid #fff; border-bottom: 1px solid #fff;
...@@ -11,6 +11,28 @@ ...@@ -11,6 +11,28 @@
.title { .title {
padding: 1em 20px; padding: 1em 20px;
input {
background: none;
border: none;
border-bottom: 1px solid #ddf;
font: inherit;
color: inherit;
width: 60%;
&::placeholder {
font-size: 0.8em;
}
}
label {
font-size: 0.9em;
padding: 5px;
background: #202;
border-radius: 5px;
cursor: pointer;
user-select: none;
}
} }
.dir-desc { .dir-desc {
......
import {Component, Input, OnInit, Output, EventEmitter} from '@angular/core'; import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {File} from '../file'; import {File} from '../file';
import {Directory} from '../directory'; import {Directory} from '../directory';
import {FileService} from '../file.service'; import {FileService} from '../file.service';
...@@ -16,13 +16,27 @@ export class FileDirCardComponent implements OnInit { ...@@ -16,13 +16,27 @@ export class FileDirCardComponent implements OnInit {
@Input() file: File; @Input() file: File;
@Input() directory: Directory; @Input() directory: Directory;
@Input() trace: number[]; @Input() trace: number[];
@Input() isNew: boolean;
@Input() parentPath: string;
deleting: boolean; deleting: boolean;
isExpanded = false; isExpanded = false;
newName = '';
isErrorDeleting = false;
isErrorCreating = false;
creating = false;
creatingNewSub = 0;
extensions = ['.cpp', '.py', '.java'];
lang = 0;
@Output() deleteFile: EventEmitter<any> = new EventEmitter(); @Output() deleteFile: EventEmitter<any> = new EventEmitter();
@Output() deleteDir: EventEmitter<any> = new EventEmitter(); @Output() deleteDir: EventEmitter<any> = new EventEmitter();
@Output() createDir: EventEmitter<any> = new EventEmitter();
@Output() createFile: EventEmitter<File> = new EventEmitter();
@Output() cancelled: EventEmitter<boolean> = new EventEmitter();
constructor(private fileService: FileService, private apiService: ApiService) { } constructor(private fileService: FileService, private apiService: ApiService) {
}
ngOnInit(): void { ngOnInit(): void {
} }
...@@ -70,4 +84,53 @@ export class FileDirCardComponent implements OnInit { ...@@ -70,4 +84,53 @@ export class FileDirCardComponent implements OnInit {
this.directory.dirs.splice(index, 1); this.directory.dirs.splice(index, 1);
} }
} }
onCreateDir(): void {
this.creating = true;
this.fileService.createDirectory(JSON.parse(this.apiService.getToken()).username, this.newName, this.parentPath)
.subscribe(data => {
if (data === '0') {
this.creating = false;
this.isErrorCreating = true;
} else {
this.createDir.emit(this.newName);
}
});
}
getRouterLink(): string {
return '/arena/file/' + encodeURIComponent(this.file.path + '/' + this.file.filename + this.file.language);
}
onCreateFile(): void {
this.creating = true;
const file: File = {
username: JSON.parse(this.apiService.getToken()).username,
filename: this.newName,
language: this.extensions[this.lang],
text: '',
path: this.parentPath
};
this.fileService.upload(file).subscribe(data => {
this.createFile.emit(file);
}, () => {
this.creating = false;
this.isErrorCreating = true;
});
}
createFileExec(file: File): void {
this.directory.files.push(file);
this.creatingNewSub = 0;
}
createDirExec(name: string): void {
this.directory.dirs.push({
name,
dirs: [],
files: [],
path: this.directory.path + this.directory.name + '/',
});
this.creatingNewSub = 0;
}
} }
...@@ -14,6 +14,8 @@ export class FileService { ...@@ -14,6 +14,8 @@ export class FileService {
uploadUrl = 'http://localhost/sfcode/backend/fileupload.php'; uploadUrl = 'http://localhost/sfcode/backend/fileupload.php';
fileListUrl = 'http://localhost/sfcode/backend/dir_tree.php'; fileListUrl = 'http://localhost/sfcode/backend/dir_tree.php';
deleteUrl = 'http://localhost/sfcode/backend/filedelete.php'; deleteUrl = 'http://localhost/sfcode/backend/filedelete.php';
fileContentUrl = 'http://localhost/sfcode/backend/get_file.php';
createDirUrl = 'http://localhost/sfcode/backend/newdir.php';
constructor(private http: HttpClient) { constructor(private http: HttpClient) {
} }
...@@ -54,4 +56,13 @@ export class FileService { ...@@ -54,4 +56,13 @@ export class FileService {
return this.http.post(this.fileListUrl, {username}); return this.http.post(this.fileListUrl, {username});
} }
getFileContent(username: string, filepath: string): Observable<any> {
return this.http.post(this.fileContentUrl, {username, file_path: filepath});
}
createDirectory(username: string, dirname: string, path: string): Observable<any> {
console.log(username, dirname, path);
return this.http.post(this.createDirUrl, {username, dirname, path});
}
} }
import {Directory} from './directory';
export interface File { export interface File {
username: string; username: string;
filename: string; filename: string;
......
<div id="tray"> <div id="tray">
<button routerLink="/arena/file/new" routerLinkActive="active" style="margin-right: 10px;">Create A File</button> <button (click)="creatingNew = 2" style="margin-right: 10px;">Create A New File</button>
<button (click)="uploadPopupActive = true" id="myBtn" style="margin-left: 10px;">Upload A File</button> <button (click)="creatingNew = 1" id="myBtn" style="margin-left: 10px;">Create New Directory</button>
</div> </div>
<div class="container"> <div class="container">
{{mainDir.dirs.length}} directories, {{mainDir.files.length}} files: {{mainDir.dirs.length}} directories, {{mainDir.files.length}} files:
</div> </div>
<app-file-dir-card *ngFor="let dir of mainDir.dirs" [isFile]="false" [directory]="dir" [level]="0" [trace]="[mainDir.dirs.indexOf(dir)]" (deleteDir)="deleteDirExec($event)" (deleteFile)="deleteFileExec($event)"></app-file-dir-card> <app-file-dir-card *ngIf="creatingNew !== 0" [parentPath]="''" [isNew]="true" [isFile]="creatingNew === 2" (createFile)="createFileExec($event)" (createDir)="createDirExec($event)" (cancelled)="creatingNew = 0"></app-file-dir-card>
<app-file-dir-card *ngFor="let file of mainDir.files" [isFile]="true" [file]="file" [level]="0" [trace]="[mainDir.files.indexOf(file)]" (deleteDir)="deleteDirExec($event)" (deleteFile)="deleteFileExec($event)"></app-file-dir-card> <app-file-dir-card *ngFor="let dir of mainDir.dirs" [isFile]="false" [directory]="dir" [level]="0" [trace]="[mainDir.dirs.indexOf(dir)]" (deleteDir)="deleteDirExec($event)" (deleteFile)="deleteFileExec($event)" [isNew]="false"></app-file-dir-card>
<app-file-dir-card *ngFor="let file of mainDir.files" [isFile]="true" [file]="file" [level]="0" [trace]="[mainDir.files.indexOf(file)]" (deleteDir)="deleteDirExec($event)" (deleteFile)="deleteFileExec($event)" [isNew]="false"></app-file-dir-card>
<div [class.open]="uploadPopupActive" id="file-upload-cover"></div> <!--<div [class.open]="uploadPopupActive" id="file-upload-cover"></div>-->
<div [class.open]="uploadPopupActive" id="file-upload-popup"> <!--<div [class.open]="uploadPopupActive" id="file-upload-popup">-->
<p>Upload a file:</p> <!-- <p>Upload a file:</p>-->
<input (change)="onChange($event)" id="file-upload-input" type="file"> <!-- <input (change)="onChange($event)" id="file-upload-input" type="file">-->
<div *ngIf="shortLink !== ''" style="margin-top: 10px"> <!-- <div *ngIf="shortLink !== ''" style="margin-top: 10px">-->
<a href="{{shortLink}}" target="_blank">Link to last upload</a> <!-- <a href="{{shortLink}}" target="_blank">Link to last upload</a>-->
</div> <!-- </div>-->
<p *ngIf="!loading"> <!-- <p *ngIf="!loading">-->
<button (click)="uploadPopupActive = false;" id="upload-cancel-btn">Close</button> <!-- <button (click)="uploadPopupActive = false;" id="upload-cancel-btn">Close</button>-->
<button (click)="onUpload()" id="file-upload-btn" [class.disabled]="fileToUpload == null || fileToUpload == undefined">Upload</button> <!-- <button (click)="onUpload()" id="file-upload-btn" [class.disabled]="fileToUpload == null || fileToUpload == undefined">Upload</button>-->
</p> <!-- </p>-->
<p *ngIf="loading" style="margin-top: 20px; text-align: center"> <!-- <p *ngIf="loading" style="margin-top: 20px; text-align: center">-->
Uploading... <!-- Uploading...-->
</p> <!-- </p>-->
</div> <!--</div>-->
...@@ -23,7 +23,7 @@ export class FileComponent implements OnInit { ...@@ -23,7 +23,7 @@ export class FileComponent implements OnInit {
loading = false; // Flag variable loading = false; // Flag variable
deleting = false; // Flag variable deleting = false; // Flag variable
fileToUpload: File = null; fileToUpload: File = null;
uploadPopupActive = false; creatingNew = 0;
constructor(private fileService: FileService, constructor(private fileService: FileService,
private dataService: ApiService) { private dataService: ApiService) {
...@@ -110,4 +110,19 @@ export class FileComponent implements OnInit { ...@@ -110,4 +110,19 @@ export class FileComponent implements OnInit {
this.mainDir.dirs.splice(index, 1); this.mainDir.dirs.splice(index, 1);
} }
} }
createFileExec(file: File): void {
this.mainDir.files.push(file);
this.creatingNew = 0;
}
createDirExec(name: string): void {
this.mainDir.dirs.push({
name,
dirs: [],
files: [],
path: '/'
});
this.creatingNew = 0;
}
} }
<div id="ide-cover" *ngIf="loadingFile">
<div id="ide-cover-text">
Loading file...
</div>
</div>
<div class="container"> <div class="container">
<div id="toggle-lang">C++</div> <div id="toggle-lang" [class.disabled]="isSaved">C++</div>
<div id="attempt"> <div id="attempt">
<span *ngIf="!isUpToDate"></span> <span *ngIf="!isUpToDate"></span>
<span id="ideFileName">{{file.filename + file.language}}</span> <span id="ideFileName">{{optimizeURI(file.path)}}{{file.filename + file.language}}</span>
<button (click)="inputField.setState(true);" id="inputBtn">Input</button> <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)="runFile()" id="runBtn" [class.disabled]="isCompiling || isError">{{isError ? 'Error' : (isCompiling ? 'Compiling...' : 'Run File')}}</button>
<button (click)="!isSaved ? this.saveField.setState(true) : updateFile();" <button (click)="!isSaved ? this.saveField.setState(true) : updateFile();"
......
...@@ -12,6 +12,10 @@ ...@@ -12,6 +12,10 @@
z-index: 100; z-index: 100;
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
&.disabled {
cursor: not-allowed;
}
} }
label { label {
...@@ -53,6 +57,25 @@ ...@@ -53,6 +57,25 @@
margin-right: 10px; 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) { @media screen and (max-width: 800px) {
.container { .container {
padding: 20px 0; padding: 20px 0;
......
import {Component, OnInit, ViewChild} from '@angular/core'; import {Component, OnInit, ViewChild} from '@angular/core';
import {Router} from '@angular/router'; import {ActivatedRoute, Router} from '@angular/router';
import {InputComponent} from '../input/input.component'; import {InputComponent} from '../input/input.component';
import {IdeCompileComponent} from '../ide-compile/ide-compile.component'; import {IdeCompileComponent} from '../ide-compile/ide-compile.component';
import {RunCodeService} from '../run-code.service'; import {RunCodeService} from '../run-code.service';
...@@ -19,6 +19,7 @@ export class IdeComponent implements OnInit { ...@@ -19,6 +19,7 @@ export class IdeComponent implements OnInit {
inp = ''; inp = '';
extensions = ['.cpp', '.py', '.java']; extensions = ['.cpp', '.py', '.java'];
loadingFile = false;
isSaved = false; isSaved = false;
isUploading = false; isUploading = false;
isCompiling = false; isCompiling = false;
...@@ -35,11 +36,12 @@ export class IdeComponent implements OnInit { ...@@ -35,11 +36,12 @@ export class IdeComponent implements OnInit {
@ViewChild(IdeCompileComponent) runField; @ViewChild(IdeCompileComponent) runField;
@ViewChild(SaveFileComponent) saveField; @ViewChild(SaveFileComponent) saveField;
constructor(public router: Router, public runCodeService: RunCodeService, private fileService: FileService, constructor(public route: ActivatedRoute, public runCodeService: RunCodeService, private fileService: FileService,
private apiService: ApiService) { private apiService: ApiService, private router: Router) {
} }
ngOnInit(): void { ngOnInit(): void {
const filepath = decodeURIComponent(this.route.snapshot.params.filepath);
const editorArea = document.getElementById('editor'); const editorArea = document.getElementById('editor');
const editor = CodeMirror.fromTextArea(editorArea as HTMLTextAreaElement, { const editor = CodeMirror.fromTextArea(editorArea as HTMLTextAreaElement, {
lineNumbers: true, lineNumbers: true,
...@@ -74,6 +76,9 @@ int main() { ...@@ -74,6 +76,9 @@ int main() {
this.file.text = code[activeLang]; this.file.text = code[activeLang];
const tl = document.getElementById('toggle-lang') as HTMLDivElement; const tl = document.getElementById('toggle-lang') as HTMLDivElement;
tl.onclick = () => { tl.onclick = () => {
if (this.isSaved) {
return;
}
activeLang = (activeLang + 1) % 3; activeLang = (activeLang + 1) % 3;
this.file.language = this.extensions[activeLang]; this.file.language = this.extensions[activeLang];
tl.innerHTML = langs[activeLang]; tl.innerHTML = langs[activeLang];
...@@ -90,6 +95,32 @@ int main() { ...@@ -90,6 +95,32 @@ int main() {
this.file.text = 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 { updateInput(val: string): void {
...@@ -118,7 +149,9 @@ int main() { ...@@ -118,7 +149,9 @@ int main() {
runFile(): void { runFile(): void {
const btn = document.getElementById('runBtn'); const btn = document.getElementById('runBtn');
if (btn.classList.contains('disabled')) {return; } if (btn.classList.contains('disabled')) {
return;
}
this.isCompiling = true; this.isCompiling = true;
this.runCodeService.compileFile(this.file) this.runCodeService.compileFile(this.file)
.subscribe(data => { .subscribe(data => {
...@@ -133,7 +166,9 @@ int main() { ...@@ -133,7 +166,9 @@ int main() {
this.isError = true; this.isError = true;
this.runField.status = '<div class="error">Runtime Error!</div>'; this.runField.status = '<div class="error">Runtime Error!</div>';
this.runField.setState(true); this.runField.setState(true);
setTimeout(() => {this.isError = false; }, 3000); setTimeout(() => {
this.isError = false;
}, 3000);
}); });
}, error => { }, error => {
console.log(error); console.log(error);
...@@ -141,7 +176,22 @@ int main() { ...@@ -141,7 +176,22 @@ int main() {
this.isError = true; this.isError = true;
this.runField.status = '<div class="error">Compilation Error!</div>'; this.runField.status = '<div class="error">Compilation Error!</div>';
this.runField.setState(true); this.runField.setState(true);
setTimeout(() => {this.isError = false; }, 3000); 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('/') + '/';
}
} }
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {FileService} from '../file.service'; import {FileService} from '../file.service';
import {File} from '../file'; import {File} from '../file';
import {Location} from '@angular/common'; import {Router} from '@angular/router';
@Component({ @Component({
selector: 'app-save-file', selector: 'app-save-file',
...@@ -15,7 +15,7 @@ export class SaveFileComponent implements OnInit { ...@@ -15,7 +15,7 @@ export class SaveFileComponent implements OnInit {
@Input() file: File; @Input() file: File;
isUploading = false; isUploading = false;
constructor(public fileService: FileService, private location: Location) { constructor(public fileService: FileService, private router: Router) {
} }
ngOnInit(): void { ngOnInit(): void {
...@@ -36,7 +36,7 @@ export class SaveFileComponent implements OnInit { ...@@ -36,7 +36,7 @@ export class SaveFileComponent implements OnInit {
this.isUploading = false; this.isUploading = false;
this.savedFile.emit(true); this.savedFile.emit(true);
this.isActive = false; this.isActive = false;
this.location.replaceState('/arena/file/' + response.key); this.router.navigate(['/arena/file/', this.file.filename + this.file.language]).then();
console.log(response); console.log(response);
}, (error) => { }, (error) => {
console.log(error); console.log(error);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment