UI HtmlCodeEditor using CodeMirror - serenity-is/Serenity GitHub Wiki
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.
- 
Download and extract CodeMirror from https://codemirror.net/codemirror.zip 
- 
Copy codemirror.css,codemirror.jsfromlibto your project.
- 
Copy xml.jsfrommode\xmlto your project. (xml.jsis 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.)
- 
Copy autorefresh.jsfromaddon\displayto your project.
- 
Edit ScriptBundles.jsonandCssBundles.jsonto include these script/css files.
- 
Obtain CodeMirror typescript definitions. 
- open command prompt in your project folder. (The folder ends with .Web)
- type npm install --save @types/codemirrorin command prompt and press enter.
- a set of files will be download to node_modules\@types\codemirror
- open node_modules/@types/codemirror/index.d.tsand add following line inEditorConfigurationinterface.
autoRefresh?: boolean;- Add a new file called HtmlCodeEditor.tsinModules/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();
        }
    }
}- Build your project and run T4 template, and the editor is ready to use.
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