解决blockly.js使用workspaceToCode方法转代码时,转不了处于禁用状态的block

397 阅读2分钟

Blockly简介

Blockly是一个将可视代码编辑器添加到Web和移动应用程序的库。 Blockly 编辑器使用互锁的图形块来表示代码概念,如变量,逻辑表达式,循环等。它使得用户可以不必关注语法细节就能直接按照编程原则进行编程。 中文文档(blockly.tortorse.com/guides/over… ps:文档写的很烂,学习的话建议下载源码结合起来看。

image.png

遇到的问题

正常来讲,如果某个block被禁用了,那说明这个block就不需要转代码,当然Blockly内部也是这么做的,但我们的需求是要把它按正常的保留下来。

解决思路

最先想到的肯定就是去翻文档了,但是找了半天,并没有找到相关的配置。 那就只能看源码了,

    //Blockly源码
  workspaceToCode(workspace?: Workspace): string {
    .....
    for (let i = 0, block; (block = blocks[i]); i++) {
      let line = this.blockToCode(block);
    }
    ......
  }

可以看到在源码里workspaceToCode方法中调用一个this.blockToCode方法。我们顺着看下这个方法

    //Blockly源码
  blockToCode(
    block: Block | null,
    opt_thisOnly?: boolean,
  ): string | [string, number] {
    .....
    if (!block.isEnabled()) {
      // Skip past this block if it is disabled.
      return opt_thisOnly ? '' : this.blockToCode(block.getNextBlock());
    }
    .....
  }

看到这里原因就很明显啦,主要是这个判断“if (!block.isEnabled())”。那最简单的方式就是直接重写一个blockToCode方法覆盖掉Blockly实例上的方法,然后把block.isEnabled()这个判断去掉就好。

//项目中的代码。
//我直接从浏览器里复制了打包后的代码blockToCode。
(Blockly as any).JavaScript.blockToCode = function (a: any, b: any) {
  false === this.isInitialized && console.warn("Generator init was not called before blockToCode was called.");
  if (!a)
    return "";
  if (a.isInsertionMarker())
    return b ? "" : this.blockToCode(a.getChildren(false)[0]);
  let c = this[a.type];
  if ("function" != typeof c)
    throw Error('Language "' + this.name_ + '" does not know how to generate code for block type "' + a.type + '".');
  c = c.call(a, a);
  if (Array.isArray(c)) {
    if (!a.outputConnection)
      throw TypeError("Expecting string from statement block: " + a.type);
    return [this.scrub_(a, c[0], b), c[1]];
  }
  if ("string" == typeof c)
    return this.STATEMENT_PREFIX && !a.suppressPrefixSuffix && (c = this.injectId(this.STATEMENT_PREFIX, a) + c), this.STATEMENT_SUFFIX && !a.suppressPrefixSuffix && (c += this.injectId(this.STATEMENT_SUFFIX, a)), this.scrub_(a, c, b);
  if (null === c)
    return "";
  throw SyntaxError("Invalid code generated: " + c);
}

OK那这个问题就被解决啦。