Skip to content

UI HtmlCodeEditor using CodeMirror

Victor Tomaili edited this page May 3, 2021 · 1 revision

Why

Why do you need a HtmlCodeEditor, when there is built-in HtmlContentEditor?

Base on CKEditor, HtmlContentEditor is a WYSIWYG editor. WYSIWYG editors are for those who have limited knowledge on HTML, CSS and JavaScript. Those editors often strips out "dangerous" JavaScript code or "fix" unclosed or missing tags. For web designers, WYSIWYG editors can be annoying.

In my recent project, I was asked to use a regular textarea for editing html code, instead of HtmlContentEditor. IMO, textarea is not preferable for editing html code. After some googling, I found CodeMirror (https://codemirror.net/).

In this Wiki, I will show you how to build a HtmlCodeEditor for Serenity using CodeMirror.

How

  1. Download and extract CodeMirror from https://codemirror.net/codemirror.zip

  2. Copy codemirror.css, codemirror.js from lib to your project.

  3. Copy xml.js from mode\xml to your project. (xml.js is for html editing. If you want to create an editor for other language, you can check out this page for more information: https://codemirror.net/mode/index.html.)

  4. Copy autorefresh.js from addon\display to your project.

  5. Edit ScriptBundles.json and CssBundles.json to include these script/css files.

  6. Obtain CodeMirror typescript definitions.

  • open command prompt in your project folder. (The folder ends with .Web)
  • type npm install --save @types/codemirror in command prompt and press enter.
  • a set of files will be download to node_modules\@types\codemirror
  1. open node_modules/@types/codemirror/index.d.ts and add following line in EditorConfiguration interface.
autoRefresh?: boolean;
  1. Add a new file called HtmlCodeEditor.ts in Modules/Common/Editors (Don't forget to change the namespace)
namespace YourProjectName {

    @Serenity.Decorators.registerEditor([Serenity.IReadOnly])
    export class HtmlCodeEditor extends Serenity.TextAreaEditor implements Serenity.IReadOnly {
        private editor: CodeMirror.EditorFromTextArea;

        constructor(input: JQuery, options: Serenity.TextAreaEditorOptions) {
            super(input, options);

            let textarea: HTMLTextAreaElement = this.element[0] as HTMLTextAreaElement;
            this.editor = CodeMirror.fromTextArea(textarea, {
                mode: "text/html",
                lineNumbers: true,
                autoRefresh: true
            });
            let height: string = (this.options.rows == undefined ? 2 : this.options.rows) * 18 + 'px';
            this.editor.setSize('100%', height);
        }

        protected set_value(value: string) {
            if (value !== undefined) {
                this.editor.setValue(value);
            }
        }

        protected get_value() {
            return this.editor.getValue();
        }

        get_readOnly(): boolean {
            return this.element.hasClass('readonly');
        }
        set_readOnly(value: boolean): void {
            console.log('set_readonly' + value);
            this.editor.setOption('readOnly', value);
            this.element.toggleClass('readonly', value);
        }

        destroy() {
            this.editor.toTextArea();
            super.destroy();
        }
    }
}
  1. Build your project and run T4 template, and the editor is ready to use.

Usage

To use HtmlCodeEditor is very simple. Just add HtmlCodeEditor attribute on the field. Because HtmlCodeEditor is inherited from TextAreaEditor, you can use Rows to control height of the editor.

Sample Code:

[FormScript("Banner.Banner")]
[BasedOnRow(typeof(Entities.BannerRow), CheckNames = true)]
public class BannerForm
{
    [LookupEditor(typeof(CountryRow)), Updatable(false)]
    public Int64 CountryId { get; set; }
    [LookupEditor(typeof(LanguageRow), CascadeField = "CountryId", CascadeFrom = "CountryId"), Updatable(false)]
    public Int64 LanguageId { get; set; }
    [HtmlCodeEditor(Rows = 25)]
    public String Contents { get; set; }
    public Boolean IsEnable { get; set; }
}

by @wezmag

Clone this wiki locally