block by nitaku abd46708a9f038da6c9a47008408c7c9

Chinese text editor

Full Screen

(…please wait while loading fonts!)

A CodeMirror editor configured to correctly display a lot of chinese characters. The following Unicode characters are covered by using the Hanazono font:

Test characters are taken from this page on ctext.org.

index.js

// Generated by CoffeeScript 1.10.0
(function() {
  new AppView({
    parent: 'body'
  });

}).call(this);

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Chinese text editor</title>
  <link type="text/css" href="index.css" rel="stylesheet"/>
  
  <link type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.min.css" rel="stylesheet"/>
  
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <script src="https://d3js.org/d3-selection-multi.v0.4.min.js"></script>
  <script src="//underscorejs.org/underscore-min.js"></script>
  
  <script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.min.js"></script>
  
  <script src="eye.js"></script>
  <script src="Editor.js"></script>
  <script src="AppView.js"></script>
</head>
<body>
  <script src="index.js"></script>
</body>
</html>

AppView.coffee

window.AppView = class AppView extends View
  constructor: (conf) ->
    super(conf)
    
    new Editor
      parent: this
      

AppView.js

// Generated by CoffeeScript 1.10.0
(function() {
  var AppView,
    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
    hasProp = {}.hasOwnProperty;

  window.AppView = AppView = (function(superClass) {
    extend(AppView, superClass);

    function AppView(conf) {
      AppView.__super__.constructor.call(this, conf);
      new Editor({
        parent: this
      });
    }

    return AppView;

  })(View);

}).call(this);

Editor.coffee

window.Editor = class Editor extends View
  constructor: (conf) ->
    super(conf)
    
    # Chrome bug workaround (https://github.com/codemirror/CodeMirror/issues/3679)
    editor_div = @d3el.append 'div'
      .attrs
        class: 'editor_div'
      .styles
        position: 'relative'

    wrapper = editor_div.append 'div'
      .styles
        position: 'absolute'
        height: '100%'
        width: '100%'

    # create the CodeMirror editor
    @cm_editor = CodeMirror wrapper.node(), {
      #lineNumbers: true,
      lineWrapping: true,
      value: '''
        義、禮、說、選
        义、礼、说、选
        㡛、㬐、㖧、䵍
        𣚣、䶅、𪘆、𦞕
        𪢨、𪪖、𫔺、𫜴
        𫝀、𫞂、𫝻、𫠝
        𫠫、𬚚、𬳕、𬺡
      '''
    }

    @cm_editor.refresh()
    _.defer () => @cm_editor.setSize() # FIXME hack for CodeMirror's linewrapping bug https://github.com/codemirror/CodeMirror/issues/1642
    @cm_editor.focus()

Editor.js

// Generated by CoffeeScript 1.10.0
(function() {
  var Editor,
    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
    hasProp = {}.hasOwnProperty;

  window.Editor = Editor = (function(superClass) {
    extend(Editor, superClass);

    function Editor(conf) {
      var editor_div, wrapper;
      Editor.__super__.constructor.call(this, conf);
      editor_div = this.d3el.append('div').attrs({
        "class": 'editor_div'
      }).styles({
        position: 'relative'
      });
      wrapper = editor_div.append('div').styles({
        position: 'absolute',
        height: '100%',
        width: '100%'
      });
      this.cm_editor = CodeMirror(wrapper.node(), {
        lineWrapping: true,
        value: '義、禮、說、選\n义、礼、说、选\n㡛、㬐、㖧、䵍\n𣚣、䶅、𪘆、𦞕\n𪢨、𪪖、𫔺、𫜴\n𫝀、𫞂、𫝻、𫠝\n𫠫、𬚚、𬳕、𬺡'
      });
      this.cm_editor.refresh();
      _.defer((function(_this) {
        return function() {
          return _this.cm_editor.setSize();
        };
      })(this));
      this.cm_editor.focus();
    }

    return Editor;

  })(View);

}).call(this);

eye.js

// Generated by CoffeeScript 1.10.0
(function() {
  var View, setup_init,
    slice = [].slice;

  setup_init = function(c, init) {
    if (c.prototype.inits == null) {
      c.prototype.inits = [];
    }
    c.prototype.inits.push(init);
    return c.prototype.init = function(conf) {
      var i, len, m, ref, results;
      ref = this.inits;
      results = [];
      for (i = 0, len = ref.length; i < len; i++) {
        m = ref[i];
        results.push(m.call(this, conf));
      }
      return results;
    };
  };

  window.observable = function(c) {
    setup_init(c, function(config) {
      this._dispatcher = d3.dispatch.apply(d3, config.events);
      return this._next_id = 0;
    });
    c.prototype.on = function(event_type_ns, callback) {
      var event_type, event_type_full, namespace, splitted_event_type_ns;
      splitted_event_type_ns = event_type_ns.split('.');
      event_type = splitted_event_type_ns[0];
      if (splitted_event_type_ns.length > 1) {
        namespace = splitted_event_type_ns[1];
      } else {
        namespace = this._next_id;
        this._next_id += 1;
      }
      event_type_full = event_type + '.' + namespace;
      this._dispatcher.on(event_type_full, callback);
      return event_type_full;
    };
    c.prototype.trigger = function() {
      var args, event_type;
      event_type = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
      this._dispatcher.apply(event_type, this, args);
      return this;
    };
    return c;
  };

  window.observer = function(c) {
    setup_init(c, function() {
      return this._bindings = [];
    });
    c.prototype.listen_to = function(observed, event, cb) {
      return this._bindings.push({
        observed: observed,
        event_type: observed.on(event, cb)
      });
    };
    c.prototype.stop_listening = function() {
      return this._bindings.forEach((function(_this) {
        return function(l) {
          return l.observed.on(l.event_type, null);
        };
      })(this));
    };
    return c;
  };

  window.View = View = (function() {
    function View(conf) {
      if (conf.tag == null) {
        conf.tag = 'div';
      }
      this.el = document.createElement(conf.tag);
      this.d3el = d3.select(this.el);
      this.d3el.classed(this.constructor.name, true);
      if (conf.parent != null) {
        this.append_to(conf.parent, conf.prepend);
      }
    }

    View.prototype.append_to = function(parent, prepend) {
      var p_el;
      if (parent.el != null) {
        p_el = parent.el;
      } else {
        if (parent.node != null) {
          p_el = parent.node();
        } else {
          p_el = d3.select(parent).node();
        }
      }
      if (prepend) {
        return p_el.insertBefore(this.el, p_el.firstChild);
      } else {
        return p_el.appendChild(this.el);
      }
    };

    View.prototype.compute_size = function() {
      this.width = this.el.getBoundingClientRect().width;
      return this.height = this.el.getBoundingClientRect().height;
    };

    return View;

  })();

}).call(this);

index.coffee

new AppView
  parent: 'body'
  

index.css

@font-face {
  font-family: HanaMinA;
  src: url(HanaMinA.ttf);
}
@font-face {
  font-family: HanaMinB;
  src: url(HanaMinB.ttf);
}

body, html {
  padding: 0;
  margin: 0;
  height: 100%;
  
}

.AppView {
  width: 100%;
  height: 100%;
}
.Editor {
  width: 100%;
  height: 100%;
}
.Editor {
  display: flex;
  flex-direction: column;
}
.Editor .editor_div {
  flex-grow: 1;
  height: 0;
}

.Editor .CodeMirror {
  height: 100%;
  font-size: 20px;
  line-height: 1.3;
  color: #333;
  background: #F7F7F7;
  font-family: HanaMinA, HanaMinB;
}