matefun.component.ts 26.3 KB
Newer Older
1
import { Component, NgModule, ViewChild, HostListener, ElementRef, ComponentRef, TemplateRef, QueryList, ViewChildren } from '@angular/core';
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { CanvasModule} from '../canvas/canvas.module';
import { CanvasComponent } from '../canvas/canvas.component';
import { Http, JsonpModule } from '@angular/http';
import { Headers, RequestOptions } from '@angular/http';
import { HaskellService } from '../../shared/services/haskell.service';
import { WebsocketService } from '../../shared/services/websocket.service';
import { UsuarioService } from '../../shared/services/usuario.service';
import { SessionService } from '../../shared/services/session.service';
import { GHCIService } from '../../shared/services/ghci.service';
import { AuthenticationService } from '../../shared/services/authentication.service';
import { GHCI_URL } from '../../shared/config';
import { Archivo } from '../../shared/objects/archivo';
import { Configuracion } from '../../shared/objects/usuario';
import { ConfirmComponent } from './confirm.component';
import { SeleccionarDirectorioComp } from './seleccionarDirectorio.component';
import { DialogService } from "ng2-bootstrap-modal";
import { CodemirrorComponent } from 'ng2-codemirror';
import { NgbPopoverConfig, NgbPopover} from '@ng-bootstrap/ng-bootstrap';
import { NgbPopoverWindow } from '@ng-bootstrap/ng-bootstrap/popover/popover';
import { NotificacionService } from '../../shared/services/notificacion.service';
Diego Rey's avatar
Diego Rey committed
22
23
import { Graph2DModule } from '../plotter/graph2D/graph2D.module';
import { Graph2DComponent } from '../plotter/graph2D/graph2D.component';
24
import { Graph3DComponent } from '../plotter/graph3D/graph3D.component';
25
26
import { TranslateService } from '@ngx-translate/core';
import { TitleCasePipe } from '../../shared/pipes/titlecase.pipe';
27
import { Router, NavigationExtras } from '@angular/router';
28
29
30

import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
31
// import 'codemirror/mode/haskell/haskell';
32
33
34
35
36
37
38
39
40
41
42
43
import 'codemirror/addon/display/panel';
import 'codemirror/addon/hint/show-hint';
import 'codemirror/addon/hint/anyword-hint';
import 'codemirror/mode/markdown/markdown';
import 'codemirror/lib/codemirror';
import 'codemirror/addon/search/search';


import 'codemirror/addon/dialog/dialog';
import 'codemirror/addon/search/search';
import 'codemirror/addon/search/matchesonscrollbar';
import 'codemirror/addon/search/jump-to-line';
44
import 'codemirror/addon/edit/matchbrackets';
45
46
import 'codemirror/addon/selection/active-line';
import 'codemirror/addon/comment/comment.js';
47

48
49
50
51
import './codemirror/matefun-mode-ES.js';
import './codemirror/matefun-mode-EN.js';
import './codemirror/addons/functions_definition_EN.js';
import './codemirror/addons/functions_definition_ES.js';
52

53
54
import * as npm from './../../../../package.json'

55
56
57
var codeMirrorRef:any;
var componentRef : any;
var focus: any;
58

59
60
61
62
63
@Component({
    moduleId: module.id,
    selector: 'matefun',     
    templateUrl: './matefun.component.html',   
    styleUrls: ['./matefun.component.scss'],  
64
    providers: [ WebsocketService, NgbPopoverConfig, UsuarioService ]
65
66
67
68
})


export class MateFunComponent {
69
70
    titlecasePipe: any;
    translateService: any;
71
72
73
74
75
76
77
78
79
80
81
82
    consoleDisable: boolean = false;
    consolaVisible: boolean = true;
    cursorPanel: any;
    cursorPanelLabel: any;
    cursorLabelInit : boolean = false;
    entrada : string = '';
    archivo : Archivo;
    copiaNombreArchivo:string;
    copiaContenidoArchivo:string;
    modificado = false;
    argumentoI = false;
    argumentoF = false;
Franco Pariani's avatar
Franco Pariani committed
83
    hintsCheck = true;
Franco Pariani's avatar
Franco Pariani committed
84
    typingCheck = true;
85
86
87
88
89
    editableLoaded = false;
    editDialogFired = false;
    archivosTree :any;
    idRecorridos: any;
    code: string ='';
90
    mostrandoDefinicion = false;
91
    archivoDefinicion: any = {};
92
93
    jump = false;
    jump_word = "";
94
95
96
97
    configCodeMirror = {
        readOnly: false,
        lineNumbers: true,
        lineWrapping : true,
98
        matchBrackets: true,
99
        styleActiveLine: true,
100
101
        extraKeys: {"Ctrl-Space": "autocomplete"},
        mode: {
102
            name: "matefun-EN", 
103
104
105
106
            globalVars: true
        },
        gutters: ["CodeMirror-linenumbers", "breakpoints"],
        theme: 'dracula',
107
108
        fontSize: 12,
        hintOptions: {
109
110
            completeSingle: false,
            closeCharacters: /[^\d\w\_]/
111
112
        },
        files: null
113
    };
114
    configCodeMirrorDefinicion: any = {};
115
    themes = ['3024-day', '3024-night', 'abcdef', 'ambiance-mobile', 'ambiance', 'base16-dark', 'base16-light', 'bespin', 'blackboard', 'cobalt', 'colorforth', 'dracula', 'duotone-dark', 'duotone-light', 'eclipse', 'elegant', 'erlang-dark', 'hopscotch', 'icecoder', 'isotope', 'lesser-dark', 'liquibyte', 'material', 'mbo', 'mdn-like', 'midnight', 'monokai', 'neat', 'neo', 'night', 'panda-syntax', 'paraiso-dark', 'paraiso-light', 'pastel-on-dark', 'railscasts', 'rubyblue', 'seti', 'solarized', 'the-matrix', 'tomorrow-night-bright', 'tomorrow-night-eighties', 'ttcn', 'twilight', 'vibrant-ink', 'xq-dark', 'xq-light', 'yeti', 'zenburn']
116
    version: string = npm.version;
117
118
119
120
121
122
123
124
125

    constructor(
        private haskellService: HaskellService,
        private authService: AuthenticationService, 
        private ghciService: GHCIService, 
        private elRef: ElementRef, 
        private notifService: NotificacionService,
        private sessionService: SessionService,
        private dialogService:DialogService,
126
        private usuarioService: UsuarioService,
127
128
        public translate: TranslateService,
        private router: Router) {
129
130
131
132
133

        // i18n
        this.translateService = translate;
        this.titlecasePipe = new TitleCasePipe();

134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
        //si el archivo fue seteado en la session. 
        this.archivo = sessionService.getArchivo();
        if(!this.archivo || !this.archivo.id){
            this.newFile();
        }
        this.copiaContenidoArchivo = this.archivo.contenido;
        this.copiaNombreArchivo = this.archivo.nombre;
        if(authService.getUser().configuracion){
            var config: Configuracion = authService.getUser().configuracion;
            if(config.fontSizeEditor<=30 && config.fontSizeEditor>=8){
                this.configCodeMirror.fontSize = config.fontSizeEditor;
            }
            if(this.themes.some(theme => theme==config.themeEditor)){
                this.configCodeMirror.theme = config.themeEditor;                
            }
            sessionStorage.setItem('codeMirrorConfig',JSON.stringify(this.configCodeMirror));
            this.argumentoI = config.argumentoI;
            this.argumentoF = config.argumentoF;

        }
        this.code = "my code";
        let svg : string = '';

Franco Pariani's avatar
Fix    
Franco Pariani committed
157
158
159
160
        for (var key in this.configCodeMirror){
            this.configCodeMirrorDefinicion[key] = this.configCodeMirror[key];
        }
        this.configCodeMirrorDefinicion['readOnly'] = true;
161
162
163
    }


164
    @ViewChildren(CodemirrorComponent) codemirror: QueryList<CodemirrorComponent>;
165
166
167
168
169
    // @ViewChild(NgbPopover) popover: NgbPopover;
    @ViewChild('popover') popover: NgbPopover;

    updateConfig(theme){
        this.configCodeMirror.theme = theme;
170
        this.codemirror.first.instance.setOption('theme', theme); 
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
        sessionStorage.setItem('codeMirrorConfig',JSON.stringify(this.configCodeMirror));
    }

    lockSaveButton (){
        this.copiaNombreArchivo = this.archivo.nombre;
        this.copiaContenidoArchivo = this.archivo.contenido;
        this.modificado = false;
    }
    

    showConfirm() {
        let disposable = this.dialogService.addDialog(ConfirmComponent, {
            title:'Está intentando editar un archivo de solo lectura', 
            message:'Está editando un archivo de solo lectura, desea continuar?'})
        .subscribe((isConfirmed)=>{

            if(isConfirmed) {
                codeMirrorRef.options.readOnly = false;
                componentRef.editDialogFired = true;
            }
191
192
        });        
    }
193

194
195
196
197
198
199
200
    /* Panel para la posición del cursor */
    makePanel() {

        var node = document.createElement("div");
        node.id = "cursorpos-panel";
        node.className = "panel bottom";
        this.cursorPanelLabel = node.appendChild(document.createElement("span"));
201
        var cm = this.codemirror.first.instance;
202
203
204
205
        var x = cm.getCursor().line;
        var y = cm.getCursor().ch; 
        x = (Number(x) + 1).toString();
        y = (Number(y) + 1).toString();
206
207
        var cursorPositionTranslate = this.translateService.get('i18n.msg.codemirror.cursorPosition').value;
        this.cursorPanelLabel.textContent = cursorPositionTranslate + ": (" + x + "," + y + ")";    
208
209


210
        this.cursorPanel = this.codemirror.first.instance.addPanel(node, {position: "bottom", stable: true});
211
212
        var that = this;
        //agregamos el evento que setea la posición
213
        this.codemirror.first.instance.on("cursorActivity",function(cm){
214
215
216
217
            var x = cm.getCursor().line;
            var y = cm.getCursor().ch; 
            x = (Number(x) + 1).toString();
            y = (Number(y) + 1).toString();
218
            that.cursorPanel.node.innerText = cursorPositionTranslate + ": (" + x + "," + y + ")";    
219
        });
220

221
        this.codemirror.first.instance.on("keyHandled",function(cm,name,evt){
222
223
224
225
226
227
            if(name.code==="Digit1" && name.ctrlKey && name.shiftKey){
                that.seleccionarDirectorio();
            } else if(name.code==="Digit2" && name.ctrlKey && name.shiftKey){
                that.saveConfig();
            }
        });
228

229
        this.codemirror.first.instance.on("keypress",function(cm,name,evt){
230

231
            if(!that.editDialogFired && JSON.parse(sessionStorage.currentUser).tipo === "docente" && cm.options.readOnly){
232
                codeMirrorRef = that.codemirror.first.instance;
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
                componentRef = that;
                that.showConfirm(); 
            }

        });
    } 

    saveConfig(){
        var config = new Configuracion();
        config.themeEditor = this.configCodeMirror.theme;
        config.fontSizeEditor = this.configCodeMirror.fontSize;
        var confUser = this.authService.getUserConfig();
        var reiniciar = confUser.argumentoF != this.argumentoF || confUser.argumentoI != this.argumentoI;
        config.argumentoF = this.argumentoF;
        config.argumentoI = this.argumentoI;
        this.usuarioService.actualizarConfiguracion(this.authService.getUser().cedula,config)
        .subscribe(
            success=> {
                //this.ghciService.consoleRef.Write("Configuración guardada"  + "\n");
                this.popover.close();
                this.authService.setUserConfig(success);
                if(reiniciar){
                    this.reiniciarInterprete();
256
257
                }

258
259
260
261
            },
            error=> {
                this.notifService.error(error);
                this.popover.close();
262
            }
Franco Pariani's avatar
Franco Pariani committed
263
264
265
266
267
268
        );
        if (!this.hintsCheck){
            delete this.configCodeMirror.extraKeys["Ctrl-Space"];
        }else{
            this.configCodeMirror.extraKeys["Ctrl-Space"] = "autocomplete";
        }
269
270
271
272
273
    }

    aumentarFuente(){
        if(this.configCodeMirror.fontSize<30){
            this.configCodeMirror.fontSize++;
274
        }
275
    }
276

277
278
279
    disminuirFuente(){
        if(this.configCodeMirror.fontSize>8){
            this.configCodeMirror.fontSize--;
280
        }
281
    }
282

283
284
    @HostListener('document:click', ['$event'])
    private documentClicked(event: MouseEvent): void {
285

286
287
        // Popover is open
        if (this.popover && this.popover.isOpen()) {
288

289
290
            // Not clicked on self element
            if (!(this.popover as any)._elementRef.nativeElement.contains(event.target)) {
291

292
293
                // Hacking typescript to access private member
                const popoverWindowRef: ComponentRef<NgbPopoverWindow> = (this.popover as any)._windowRef;
294

295
296
297
                // If clicked outside popover window
                if (!popoverWindowRef.location.nativeElement.contains(event.target)) {
                    this.popover.close();
298
299
300
                }
            }
        }
301
    }
302

303
    ngOnInit() {
304
        window['matefunComponent'] = { component: this };
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343

        this.ghciService.rendered(); 


        this.haskellService.getArchivos(this.authService.getUser().cedula)
        .subscribe(
            archivos => {
                //.filter(function(a){return !a.eliminado})
                this.buildTreeFromList(archivos);

            }, 
            error => console.log("Error al obtener los archivos del alumno") 
            );

        function KeyPress(e) {

            var evtobj = window.event? event : e
            if (evtobj.keyCode == 90 && evtobj.ctrlKey){
                //alert("Ctrl+z")
            };
            if(evtobj.key.toLowerCase() ==="a" && evtobj.ctrlKey){
                componentRef.seleccionarDirectorio();
                return false;
            }else if(evtobj.key.toLowerCase() ==="e" && evtobj.ctrlKey){
                componentRef.downloadFile();
                return false;
            } else if(evtobj.key.toLowerCase() ==="r" && evtobj.ctrlKey){
                componentRef.reiniciarInterprete();
                return false;
            } else if(evtobj.key.toLowerCase() ==="g" && evtobj.ctrlKey){
                componentRef.guardarArchivo();
                return false;
            } else if(evtobj.key.toLowerCase() ==="o" && evtobj.ctrlKey){
                document.getElementById("popover").click();
                return false;
            } else if(evtobj.ctrlKey && evtobj.altKey && evtobj.key.toLowerCase() ==="p"){
                document.getElementById("ProgramBtn").click();
                var that  = componentRef;
                setTimeout(function() {
344
                    that.codemirror.first.instance.focus();
345
                },250);
346
                componentRef.codemirror.first.instance.focus();
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
                focus ="program";
                return false;
            }  else if(evtobj.ctrlKey && evtobj.altKey && evtobj.key.toLowerCase() ==="c"){
                componentRef.ghciService.focusConsole();
                focus = "consola";
                return false;
            }  else if(evtobj.ctrlKey && evtobj.altKey && evtobj.key.toLowerCase() ==="f"){
                document.getElementById("FigurasBtn").click()
                componentRef.ghciService.focusConsole();
                focus = "graficas";
                return false;
            }  else if(evtobj.key.toLowerCase() ==="p" && evtobj.ctrlKey && !evtobj.altKey){
                componentRef.runCode();
                return false;
            } 
362
        }
363
        document.onkeydown = KeyPress;
Franco Pariani's avatar
Franco Pariani committed
364
365
366
367
368
369
370
371

        let currentSession = sessionStorage.getItem("currentUser"); 
        let langCode = currentSession ? JSON.parse(currentSession).language : 'es';
        if (langCode == 'es'){
            this.configCodeMirror.mode.name = "matefun-ES";
        }else if (langCode == 'en'){
            this.configCodeMirror.mode.name = "matefun-EN";
        }
372
    }
373

374
    ngAfterViewInit() {
375
376
377
378
        this.codemirror.last.instance.on('change', () => {
            this.makeAJump();
        });

379
        componentRef = this;
380
        if(this.codemirror.first.instance!=null && !this.cursorLabelInit){
381
            this.cursorLabelInit = true;
382
            this.codemirror.first.instance.setOption('theme', this.configCodeMirror.theme);
383
384
            this.makePanel();    
        }
385
        if(!this.editableLoaded && this.codemirror.first.instance!=null &&(this.sessionService.archivo.editable!==undefined)){
386
387
            try{
                var editable = this.sessionService.archivo.editable && (this.sessionService.archivo.estado == 'Edicion' || this.sessionService.archivo.estado == 'Devuelto');
388
                this.codemirror.first.instance.options.readOnly = !editable;
389
                this.editableLoaded = true;
390
391


392
393
394
395
            } catch(err) {
                return;

            }
396
397
        }

398
399
    }
    
400
401
402
403
404
405
406
    makeAJump(){
        if (this.jump){
            this.jump = false;
            this.jumpExternalFile(this.jump_word);
        }
    }
    
407
408
409
410
411
412
413
414
415
416
    htmlEncode(value:string){
        return value
        .replace('Prelude> ','')
        .replace(/&/g, '&amp;')
        .replace(/\s/g, '&nbsp;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;');
    }
417

418
    // @ViewChild(CanvasComponent) canvasC: CanvasComponent;
419
    @ViewChild(Graph3DComponent) graph3DComp: Graph3DComponent;
420

Diego Rey's avatar
Diego Rey committed
421
    @ViewChild(Graph2DComponent) graph2DComp: Graph2DComponent;
422

423
424
425
426
    funcionSTR: string = 'Math.sin(x)*x*x-20';
    consola: string = '';
    command: string = '';
    tipo: number = 1;
427

428
429
430
431
    private onKey = function (value: string) {
        this.funcionSTR = value;
        this.archivo.contenido = value;
    }
432

433
434
435
    private writeCommand = function (value: string){
        this.command = value.split("\n")[value.split("\n").length - 1];
    }
436

437
438
439
440
    private selectFunction = function() {
        this.tipo = 1;
        this.funcionSTR = "Math.sin(x)*x*x-20";
    }
441

442
443
444
445
    private selectElipse = function() {
        this.tipo = 2;
        this.funcionSTR = "elipse(x,y,radioX, radioY, rotacion_en_grados)";
    }
446

447
448
449
450
    private selectCircle = function() {
        this.tipo = 3;
        this.funcionSTR = "circulo(x,y,radio)";
    }
451

452
453
454
    private elipse = function(x: number, y: number, radiusX: number, radiusY: number, rotation: number) {
        return [x, y, radiusX, radiusY, rotation];
    }
455

456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
    private circulo = function(x: number, y: number, radius: number) {
        return [x, y, radius];
    }

    inputConsola(text:any){
        this.entrada = text;            
    }
    newFile(){
        this.archivo = new Archivo();
        this.archivo.cedulaCreador = this.authService.getUser().cedula;
        this.archivo.contenido = "";
        this.archivo.nombre = "";
        this.copiaNombreArchivo = '';
        this.copiaContenidoArchivo = '';
    }

472
    archivoModificado(event){
Franco Pariani's avatar
Franco Pariani committed
473
        if (this.hintsCheck && !event.ctrlKey && !event.altKey){
474
            if (/^[\w\_\d]$/.test(event.key) || event.key == 'Enter'){
475
476
                this.codemirror.first.instance.options.files = this.archivosTree;
                this.codemirror.first.instance.showHint(event);
477
            }
478
479
480
481
482
            if(this.copiaNombreArchivo!=this.archivo.nombre || this.copiaContenidoArchivo != this.archivo.contenido){
                this.modificado = true;
            }else{
                this.modificado = false;
            }
483
484
485
486
487
488
        }else if (event.ctrlKey && event.shiftKey && event.key == 'K') this.codemirror.first.instance.toggleComment();
        else if (event.altKey && event.key == '.') this.codemirror.first.instance.jumpToDefinition(this.archivosTree, this.codemirror.first.instance.doc, event);
    }

    goToFilesPreview(file_found, word){
        this.mostrandoDefinicion = true;
Franco Pariani's avatar
Fix    
Franco Pariani committed
489
490
491
492
        for (var key in this.configCodeMirror){
            this.configCodeMirrorDefinicion[key] = this.configCodeMirror[key];
        }
        this.configCodeMirrorDefinicion['readOnly'] = true;
493
494
495
496
497
498
499
500
        this.archivoDefinicion = this.archivosTree.archivos.filter(a => a.id == parseInt(file_found.id))[0];
        this.jump = true;  
        this.jump_word = word;
        this.jumpExternalFile(word);
    }

    jumpExternalFile(word){
        this.codemirror.last.instance.jumpToDefinitionByWord(this.codemirror.last.instance.doc, word);
501
    }
502

503
    clickEnEditor(event){
Franco Pariani's avatar
Fix    
Franco Pariani committed
504
505
506
507
        if (this.typingCheck){
            let currentSession = sessionStorage.getItem("currentUser"); 
            let langCode = currentSession ? JSON.parse(currentSession).language : 'es';
            if (langCode == 'en')
508
                this.codemirror.first.instance.functionDefinitionEN(this.archivo.nombre, this.archivosTree.archivos, this.codemirror.first.instance.doc, event);
Franco Pariani's avatar
Fix    
Franco Pariani committed
509
            else if (langCode == 'es')
510
                this.codemirror.first.instance.functionDefinitionES(this.archivo.nombre, this.archivosTree.archivos, this.codemirror.first.instance.doc, event);
511
    }
512
513
    }

514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
    guardarArchivo(){
        var regex = /^[A-Z]/
        if(this.archivo.nombre.trim() == ""){
            this.notifService.error("Nombre de archivo sin especificar");
        }else if (!regex.test(this.archivo.nombre)){
            this.notifService.error("Nombre de archivo debe iniciar con mayusula.")
        }else{
            if(this.archivo.id){
                this.haskellService.editarArchivo(this.archivo.id, this.archivo)
                .subscribe(
                    archivo => {
                        //this.ghciService.consoleRef.Write("Editar archivo: " + this.archivo.nombre + "\n");
                        this.archivo = archivo;
                        this.lockSaveButton();
                    }, 
                    error => {
                        this.notifService.error(error);
                    });
532
            }else{
533
534
535
536
537
538
539
540
541
542
543
                this.haskellService.crearArchivo(this.archivo)
                .subscribe(
                    archivo => {
                        //this.ghciService.consoleRef.Write("Archivo creado: " + this.archivo.nombre + "\n");
                        this.archivo = archivo;
                        this.lockSaveButton();
                    }, 
                    error => {
                        this.notifService.error(error);
                    });

544
545
            }
        }
546
547
    }
    runCode(){
548
        this.ghciService.setCodemirrorRef(this.codemirror.first.instance);
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
        this.ghciService.resetGutters();
        var regex = /^[A-Z]/
        if(this.archivo.nombre.trim() == ""){
            this.notifService.error("Nombre de archivo sin especificar");
        }else if (!regex.test(this.archivo.nombre)){
            this.notifService.error("Nombre de archivo debe iniciar con mayusula.")
        }else{

            var resultado = this.sessionService.cargarDependencias(this.archivo);
            if(resultado["status"]==="miss"){
                this.ghciService.outputConsole("Error: No se encuentra el archivo " + resultado["nombre"] + "\n");
                return;
            }
            if(this.archivo.id){
                if(this.archivo.editable || this.authService.getUser().tipo == 'docente'){
564
565
566
567
                    this.haskellService.editarArchivo(this.archivo.id, this.archivo)
                    .subscribe(
                        archivo => {
                            this.archivo = archivo;
568
569
570
571
572
573
574
575
                            var list = this.sessionService.getDependencias(),
                            idList = [];
                            for(var l in list){
                                idList.push(list[l].id);
                            }
                            if(!idList.some(id => id ==archivo.id)){
                                idList.push(archivo.id);
                            }
576
                            this.lockSaveButton();
577
                            this.ghciService.loadFile(archivo.id,archivo.nombre,idList);
578
579
580
581
582
                        }, 
                        error => {
                            this.notifService.error(error);
                        });
                }else{
583
584
585
586
                    var list = this.sessionService.getDependencias(),
                    idList = [];
                    for(var l in list){
                        idList.push(list[l].id);
587
                    }
588
589
590
                    if(!idList.some(id => id ==this.archivo.id)){
                        idList.push(this.archivo.id);
                    }
591
                    this.ghciService.loadFile(this.archivo.id,this.archivo.nombre,idList);
592
                }
593
594
595
596
597
598
            }else{
                this.haskellService.crearArchivo(this.archivo)
                .subscribe(
                    archivo => {
                        this.archivo = archivo;
                        this.lockSaveButton();
599
                        this.ghciService.loadFile(archivo.id,archivo.nombre,[]);
600
601
602
603
                    }, 
                    error => {
                        this.notifService.error(error);
                    });
604
605
            }
        }
606
        this.ghciService.focusConsole();
607

608
609
610
611
612
    }
    download(filename, text) {
        var element = document.createElement('a');
        element.setAttribute('href', 'data:application/octet-stream,' + encodeURIComponent(text));
        element.setAttribute('download', filename+ ".mf");
613

614
615
        element.style.display = 'none';
        document.body.appendChild(element);
616

617
        element.click();
618

619
620
621
622
623
624
625
        document.body.removeChild(element);
    }
    downloadFile(){
        var nom = this.archivo.nombre;
        var content = this.archivo.contenido;
        if(nom!= undefined && nom!="" && content!= undefined && content !=""){
            this.download(nom , content);
626
627
        }

628
629
630
631
    }
    reiniciarInterprete(){
        this.ghciService.reiniciarInterprete();
    }
632

633
634
635
    toggleConsole(){
        this.consolaVisible = !this.consolaVisible;
    }
636

637
638
639
640
641
642
643
644
645
646
647
    seleccionarDirectorio(){
        this.archivosTree = this.sessionService.getArchivos(undefined);
        var that = this;
        let disposable = this.dialogService.addDialog(SeleccionarDirectorioComp, {
            title:'', 
            message:'',
            archivos:this.archivosTree,
            directorioActual:this.archivosTree,
            nombre:'',
            parent:this})
        .subscribe((isConfirmed)=>{
648

649
            if(isConfirmed) {
650
651


652
653
654
655
656
                //codeMirrorRef.options.readOnly = false;
                //componentRef.editDialogFired = true;
            }
        });
    }
657
658


659
    buildTreeFromList (archivos){
660
661


662
663
664
665
666
667
668
669
        this.sessionService.setArchivosList(archivos);
        var root :Archivo;

        for(var a in archivos){
            var arch = archivos[a];
            if(arch.padreId===-1){
                root = arch;
            } 
670
        }
671
672
673
674
675
676
677
678
679
680
        this.idRecorridos = [root.id];
        var archivos2 = archivos.filter(
            function(a){
                return a.id!==root.id;
            }
            );
        var tree = this.buildTree(archivos2,root);
        this.archivosTree = tree;
        this.sessionService.setArchivosTree(tree);
    }
681
682


683
684
685
686
687
688
689
    buildTree(archivos, root){
        root.archivos = this.getArchivos(root.id,archivos);
        for(var a in root.archivos){
            if(root.archivos[a].directorio && this.idRecorridos[root.archivos[a].id] === undefined){
                var id = root.archivos[a].id;
                var archivos2 = archivos.filter(function(a){return a.id!==id});
                root.archivos[a] = this.buildTree(archivos2 ,root.archivos[a]);
690
691
            }
        }
692
693
        return root;
    }
694

695
696
697
698
699
700
    getArchivos(id,archivos){
        return archivos.filter(
            function(a){
                return a.padreId === id;
            });
    }
701

702
703
704
705
706
    onChangeTab(event) {
        if (event.nextId == 'FigurasBtn3D') {
            this.graph3DComp.onActivate();
        }
    }
707
}