适用于 ghost 3.0.2

修复内容:

  1. 中文输入法在新行时,输入会阻断第一个字符
  2. 中文输入法在选词过程中,执行删除、换行、tab等行为会影响输入
  3. (个人偏好)mac系统下,cmd+delete 删除光标下至行首字符

社区中8个月前已有人提交了修复内容,但是Ghost团队一直未更新 @tryghost/mobiledoc-kit。

对于这个事情博主个人是挺恼怒的,因为这类 issues 在 TryGhost/Ghost 仓库中有不少,当前的 ghost使用非英语语种的输入法体验非常糟糕,但是 ghost 团队仅仅提出请将PR提交到 @tryghost/mobiledoc-kit 中就关闭了issues;并且 ghost 团队, 自己也一直没有修复自己的另一个仓库 @tryghost/mobiledoc-kit。

所以是否将以下内容以PR的形式提交给 @tryghost/mobiledoc-kit 还在考虑。

索性我这里有一个临时的解决方案:

拷贝容器中编辑器的前端代码

以 docker 运行的 ghost 为例,我们进入ghost容器(假设 ghost 容器名为 ghost),查找我们要修改的文件名:

$ docker exect -it ghost /bin/bash
$ cd /var/lib/ghost/versions/3.0.2/core/built/assets/
$ ls

我们发现 ghost@3.0.2 编译的文件名为: vendor.min-4fe157c12fff6582cb230b46e7c16b15.js

然后拷贝出编译后的前端代码:

docker cp ghost:/var/lib/ghost/versions/3.0.2/core/built/assets/vendor.min-4fe157c12fff6582cb230b46e7c16b15.js ~/vendor.min-4fe157c12fff6582cb230b46e7c16b15.js

修改前端代码:

我们在 vendor.min-xxxx.js 中找到 {key:"keydown",value:function(e){...}}代码块(我们可以上下文搜索 isHorizontalArrowWithoutModifiersOtherThanShift 字符);

修改成以下内容, 因为 vendor.min 是用于生产的代码,js文件内容都被压缩了,所以替换成以下代码需要仔细注意它在代码块中的位置:

// 大致在6793行
{key:"keydown",value:function(event) {

  let { editor } = this;
  if (!editor.hasCursor()) { return; }
  if (!editor.isEditable) { return; }

  // let key = Key.fromEvent(event);
  let key = r.default.fromEvent(event)
  this._updateModifiersFromKey(key, {isDown:true});

  if (editor.handleKeyCommand(event)) { return; }

  if (editor.post.isBlank) {
    editor._insertEmptyMarkupSectionAtCursor();
  }

  let range = editor.range;
  let isAfterDelete = false;

  switch(true) {
    case key.isIME(): {
      if (range && range.head.offset === 0) {
        this._textInputHandler.handle(key.toString());
      }
      event.preventDefault();
      break;
    }
    // FIXME This should be restricted to only card/atom boundaries
    case key.isHorizontalArrowWithoutModifiersOtherThanShift(): {
      let newRange;
      if (key.isShift()) {
        newRange = range.extend(key.direction * 1);
      } else {
        newRange = range.move(key.direction);
      }

      editor.selectRange(newRange);
      event.preventDefault();
      break;
    }
    case key.isDelete(): {
      let { direction } = key;
      let unit = 'char';
      if(s.default.isMac() && key.metaKey) {
        unit = 'line';
        editor.performDelete({direction, unit});
        break;
      } else if (key.altKey && s.default.isMac()) {
        unit = 'word';
      } else if (key.ctrlKey && !s.default.isMac()) {
        unit = 'word';
      }
      editor.performDelete({direction, unit});
      event.preventDefault();
      break;
    }
    case key.isEnter():
      this._textInputHandler.handleNewLine();
      editor.handleNewline(event);
      break;
    case key.isTab():
      // Handle tab here because it does not fire a `keypress` event
      event.preventDefault();
      this._textInputHandler.handle(key.toString());
      break;
  }

}}

将修改后的前端代码拷贝回docker容器

docker cp ~/vendor.min-4fe157c12fff6582cb230b46e7c16b15.js ghost:/var/lib/ghost/versions/3.0.2/core/built/assets/vendor.min-4fe157c12fff6582cb230b46e7c16b15.js

由于JS脚本的名称没有变化,所以浏览器会使用历史的脚本缓存。在做完以上修改后,我们不需要重启docker容器,只需要清空浏览器缓存以生效内容。

如果觉得清空浏览器缓存会影响其他历史体验,可以访问自己的ghost编辑器页面,然后打开浏览器开发者面板 ( Chrome 在 mac 下使用 cmd+alt+i ):

如图,切换到 Network 面包,钩上 Disable cache,然后刷新页面,浏览器会忽略缓存加载资源,当加载完毕之后,我们修改的前端代码已经生效,记得取消 Disable cache 选项。

相关资料:

如何判断中文输入状态?

根据 W3c Editor`s Draft 的规范,当输入法过程中,keycode 为 229:

http://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html#fixed-virtual-key-codes

keycode === 229

被关闭的PR:这个PR修复了除了新行输入的其他问题,但是没有被采用

Editor: IME input problem · Issue #9801 · TryGhost/Ghost
This is an issue in the upstream mobiledoc-kit library and the underlying problem is being tracked in multiple places on that repo, with the two most prominent issues being: bustle/mobiledoc-kit#58...