Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can not use some addons #145

Closed
johaven opened this issue Nov 4, 2018 · 17 comments
Closed

Can not use some addons #145

johaven opened this issue Nov 4, 2018 · 17 comments

Comments

@johaven
Copy link

johaven commented Nov 4, 2018

I try to use this addon: https://codemirror.net/demo/loadmode.html

The idea is to put all folder languages in my assets dir, and give formatted url etc ...

How can i access to this variable https://github.com/codemirror/CodeMirror/blob/29e338b8c1f27ade4502839877df7afd49584479/demo/loadmode.html#L65 with ngx-codemirror ?

@scttcper
Copy link
Owner

scttcper commented Nov 5, 2018

accessing the editor property

use a viewchild ref to access the component and then its at the public codemirror property https://github.com/TypeCtrl/ngx-codemirror/blob/master/src/lib/codemirror.component.ts#L87

@johaven
Copy link
Author

johaven commented Nov 5, 2018

Thank you :)

@johaven
Copy link
Author

johaven commented Nov 5, 2018

Another problem: CodeMirror.autoLoadMode(instance, mode) must be called but this.codeMirror.codeMirror.autoLoadMode is not a function

After reading code of loadmode.js: https://github.com/codemirror/CodeMirror/blob/29e338b8c1f27ade4502839877df7afd49584479/addon/mode/loadmode.js#L58

The function seems to not be declared properly on codeMirror instance

@johaven
Copy link
Author

johaven commented Nov 5, 2018

I think is related to: codemirror/codemirror5#5484

Your import seems to be the same as described: https://github.com/TypeCtrl/ngx-codemirror/blob/d5cafceb528b8b95643bd0fa3a7ff858a5c63582/src/lib/codemirror.component.ts#L23 and nothing is correctly declared to the "fake" instance described.

@scttcper
Copy link
Owner

scttcper commented Nov 5, 2018

its imported down further, those are just @types being imported at the top
https://github.com/TypeCtrl/ngx-codemirror/blob/d5cafceb528b8b95643bd0fa3a7ff858a5c63582/src/lib/codemirror.component.ts#L98

You might make sure you've included your plugin correctly from the first step of use https://github.com/TypeCtrl/ngx-codemirror#use or make sure the codemirror instance has been created when your code runs

@johaven
Copy link
Author

johaven commented Nov 6, 2018

capture d ecran 2018-11-06 a 18 05 53

console.log(this.codeMirror.codeMirror), instance is ok. Viewer is ok, but when addons are loaded, no functions are inherited

capture d ecran 2018-11-06 a 18 05 32

Same problem with the meta mod:
capture d ecran 2018-11-06 a 18 16 10

Just for information, I use angular 6

@johaven
Copy link
Author

johaven commented Nov 11, 2018

This seems to be the case for all the addons

@johaven johaven changed the title Lazy Mode Loading Can not use addons Nov 11, 2018
@johaven
Copy link
Author

johaven commented Nov 11, 2018

After a lot of debugging, it seems require creates a scoped instance of CodeMirror.
Addons have to find a global instance of CodeMirror in plain mode to correctly work.
fromTextArea doesn't return all CodeMirror object (this is why i did not find the addons functions).

My final solution is to mix global instance and this component.
For this i need to declare in angular.json all the scripts to import:

"scripts": [
              "node_modules/codemirror/lib/codemirror.js",
              "node_modules/codemirror/mode/meta.js",
              "node_modules/codemirror/addon/mode/loadmode.js"
            ]

If we use fromTextArea from scoped instance, the setOption function will not work.
In ngx-codemirror component replace:

declare var require: any; // remove this
const { fromTextArea } = require('codemirror');
this.codeMirror = fromTextArea(this.ref.nativeElement, this._options);

by:

declare var CodeMirror: any; // replaced by "var require..."
this.codeMirror = CodeMirror.fromTextArea(this.ref.nativeElement, this._options);

In my internal component i use declare var CodeMirror: any to access all functions (ref is the childView of ngx-codemirror component)

ngAfterViewInit() {
        CodeMirror.modeURL = this.modeUrl
        const mode = CodeMirror.findModeByFileName(this.file.name).mode // this function is loaded by meta addon
        CodeMirror.autoLoadMode(this.ref.codeMirror, mode) // this function is loaded by loadmode addon
        this.ref.codeMirror.setOption('mode', mode)
    }

@maximelafarie
Copy link

Importing addons like modes as described in the README works perfectly. Here's my main.ts file:

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

// Import your required language in main.ts or at the root of your application
// see https://codemirror.net/mode/index.html
import 'codemirror/mode/javascript/javascript';
import 'codemirror/mode/css/css';
import 'codemirror/mode/htmlmixed/htmlmixed';

import 'codemirror/addon/edit/matchbrackets';
import 'codemirror/addon/edit/closetag';
import 'codemirror/addon/selection/active-line';


if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

and here's my options object to enable the above addons:

editorOptions = {
  lineNumbers: true,
  autoCloseTags: true,
  styleActiveLine: true,
  theme: 'monokai',
  mode: 'text/html',
  // define Emmet output profile
  profile: 'xhtml'
};

Btw, thank you a lot @scttcper for this awesome ngx wrapper for codemirror! 🙌
Cheers!

@johaven
Copy link
Author

johaven commented Nov 21, 2018

This only works for addons that affect the editor (CodeMirror.fromTextArea)

@maximelafarie
Copy link

@johaven I got it! Good to know. 👍

@johaven johaven changed the title Can not use addons Can not use some addons Nov 21, 2018
@scttcper
Copy link
Owner

@johaven i'm not sure how to fix it for your case. You might try copying out the component and instantiating codemirror as you require, unless there's a way to make it work for everyone's general use.

@johaven
Copy link
Author

johaven commented Nov 21, 2018

@scttcper This is what i do for the time being.
But if you replace the 2 lines of code, it should work for everyone:

declare var CodeMirror: any; // replaced by "var require..."
this.codeMirror = CodeMirror.fromTextArea(this.ref.nativeElement, this._options);

If people want to use other addons like me, they will only have to load the libraries via the Angular scripts tag above, for others it will work the same way.

@james-powis
Copy link

james-powis commented Feb 6, 2019

I am attempting to do something similar except in my case is to dynamically define the mode and load it on the fly based on a matrix of user provided data... @johaven could you provide a StackBlitz showing what you did to get loadmode functional? because I am hitting a brick wall trying to deduce this thread.

@johaven
Copy link
Author

johaven commented Feb 9, 2019

I do not have much time but I will give you my configuration.

angular.json

"scripts": [
              "node_modules/codemirror/lib/codemirror.js",
              "node_modules/codemirror/mode/meta.js",
              "node_modules/codemirror/addon/mode/loadmode.js",
              "node_modules/codemirror/addon/mode/overlay.js"
            ]

codemirror.component.ts diff I declare this modified component in my module.
capture d ecran 2019-02-09 a 09 59 25

Usage example

import {AfterViewInit, Component, Input, OnInit, ViewChild, ViewEncapsulation} from '@angular/core'
import {HttpClient} from '@angular/common/http'

declare var CodeMirror: any

@Component({
    selector: 'app-files-viewer-text',
    encapsulation: ViewEncapsulation.None,
    styles: [`
      .CodeMirror {
        height: 100%
      }
    `],
    template: `
      <div [style.height.px]="currentHeight">
        <ngx-codemirror #CodeMirror [(ngModel)]="content" [options]=options></ngx-codemirror>
      </div>`
})
export class FilesViewerTextComponent implements OnInit, AfterViewInit {
    @ViewChild('CodeMirror') ref: any
    @Input() currentHeight: number
    @Input() file: any
    @Input() fileUrl: string
    private readonly modeUrl = '/static/assets/codemirror/mode/%N/%N.js'
    public content: string
    public options: any = {lineNumbers: true, readOnly: true, theme: 'material', mode: 'null'}
    private mode: string = null

    constructor(private http: HttpClient) {
        CodeMirror.modeURL = this.modeUrl
    }

    ngOnInit() {
        const detectedMode = CodeMirror.findModeByFileName(this.file.name)
        if (detectedMode) {
            this.mode = detectedMode.mode
            this.http.get(this.fileUrl, {responseType: 'text'}).subscribe((data: string) => this.content = data)
        } else {
            this.content = 'This file contains binary data that can not be read'
        }
    }

    ngAfterViewInit() {
        if (this.mode) {
            CodeMirror.autoLoadMode(this.ref.codeMirror, this.mode)
            this.ref.codeMirror.setOption('mode', this.mode)
        }
    }
}

@Fillonj
Copy link

Fillonj commented Feb 2, 2022

Hello, i also had problems to use the mergeView addon, but finally made it, so here is my sample codemirror-merge-view

@sp90
Copy link
Contributor

sp90 commented Feb 1, 2023

@scttcper this can be closed

@scttcper scttcper closed this as completed Feb 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants