Tiện ích và yếu tố đột biến

Phần mở rộng là các hàm chạy trên mỗi khối thuộc một loại cho trước vì khối này đã tạo. Các khối này thường thêm một số cấu hình hoặc hành vi tuỳ chỉnh vào khối.

Biến đổi là một loại tiện ích đặc biệt thêm chuyển đổi tuần tự tuỳ chỉnh và thành một khối.

Phần mở rộng

Phần mở rộng là các hàm chạy trên mỗi khối thuộc một loại cho trước vì khối này đã tạo. Họ có thể thêm cấu hình tuỳ chỉnh (ví dụ: đặt phần chú thích của quy tắc chặn) hoặc hành vi tuỳ chỉnh (ví dụ: thêm một trình nghe sự kiện vào khối).

// This extension sets the block's tooltip to be a function which displays
// the parent block's tooltip (if it exists).
Blockly.Extensions.register(
    'parent_tooltip_extension',
    function() { // this refers to the block that the extension is being run on
      var thisBlock = this;
      this.setTooltip(function() {
        var parent = thisBlock.getParent();
        return (parent && parent.getInputsInline() && parent.tooltip) ||
            Blockly.Msg.MATH_NUMBER_TOOLTIP;
      });
    });

Tiện ích phải được "đăng ký" để chúng có thể liên kết với một chuỗi . Sau đó, bạn có thể chỉ định khoá chuỗi này cho thuộc tính extensions của JSON của loại khối xác định để áp dụng tiện ích mở rộng cho khối.

{
 //...,
 "extensions": ["parent_tooltip_extension",]
}

Bạn cũng có thể thêm nhiều phần mở rộng cùng một lúc. Xin lưu ý rằng extensions thuộc tính phải là một mảng, ngay cả khi bạn chỉ áp dụng một phần mở rộng.

{
  //...,
  "extensions": ["parent_tooltip_extension", "break_warning_extension"],
}

Mixin (Nhạc kết hợp)

Blockly cũng cung cấp một phương thức thuận tiện cho các trường hợp mà bạn muốn thêm một số thuộc tính/hàm trợ giúp vào một khối, nhưng không chạy chúng ngay lập tức. Chiến dịch này hoạt động bằng cách cho phép bạn đăng ký một sản phẩm hỗn hợp chứa tất cả các thuộc tính/phương thức bổ sung của bạn. Đối tượng trộn sau đó được bao bọc trong một hàm áp dụng trộn mỗi khi một thực thể của loại khối đã cho sẽ được tạo.

Blockly.Extensions.registerMixin('my_mixin', {
  someProperty: 'a cool value',

  someMethod: function() {
    // Do something cool!
  }
))`

Khoá chuỗi liên kết với trình kết hợp có thể được tham chiếu trong JSON giống như bất kỳ khoá nào khác tiện ích.

{
 //...,
 "extensions": ["my_mixin"],
}

Biến thể

Biến đổi (mutator) là một loại tiện ích mở rộng đặc biệt bổ sung thêm chuỗi tuần tự (thêm được lưu và tải) vào một khối. Ví dụ: tham số tích hợp Các khối controls_iflist_create_with cần thêm quá trình chuyển đổi tuần tự để chúng có thể lưu số lượng đầu vào mà họ có.

Lưu ý rằng việc thay đổi hình dạng khối không nhất thiết có nghĩa là bạn cần chuyển đổi tuần tự bổ sung. Ví dụ: khối math_number_property thay đổi nhưng nó thực hiện việc đó dựa trên trường thả xuống, có giá trị đã được nhận đã chuyển đổi tuần tự. Như vậy, nó chỉ có thể sử dụng trường trình xác thực và không cần một người biến đổi.

Xem chuyển đổi tuần tự cho thêm thông tin về thời điểm bạn cần và khi nào không cần biến thể.

Trình đột biến cũng cung cấp một giao diện người dùng tích hợp sẵn để người dùng thay đổi hình dạng của khối nếu bạn cung cấp một số phương thức tuỳ chọn.

Móc chuyển đổi tuần tự

Các đột biến có 2 cặp nối tiếp nối tuần tự mà chúng hoạt động. Một cặp móc hoạt động với hệ thống chuyển đổi tuần tự JSON mới, còn cặp còn lại hoạt động với hệ thống chuyển đổi tuần tự XML cũ. Bạn phải cung cấp ít nhất một trong các cặp này.

save ExtraState và loadExtraState

saveExtraStateloadExtraState là các hook chuyển đổi tuần tự hoạt động với hệ thống chuyển đổi tuần tự JSON mới. saveExtraState trả về một tệp JSON có thể chuyển đổi tuần tự giá trị đại diện cho trạng thái bổ sung của khối và loadExtraState chấp nhận cùng một giá trị JSON có thể chuyển đổi tuần tự và áp dụng giá trị đó cho khối.

// These are the serialization hooks for the lists_create_with block.
saveExtraState: function() {
  return {
    'itemCount': this.itemCount_,
  };
},

loadExtraState: function(state) {
  this.itemCount_ = state['itemCount'];
  // This is a helper function which adds or removes inputs from the block.
  this.updateShape_();
},

JSON thu được sẽ có dạng như sau:

{
  "type": "lists_create_with",
  "extraState": {
    "itemCount": 3 // or whatever the count is
  }
}
Không có tiểu bang nào

Nếu khối của bạn ở trạng thái mặc định khi được chuyển đổi tuần tự, thì Phương thức saveExtraState có thể trả về null để cho biết điều này. Nếu Phương thức saveExtraState trả về null, sau đó không thêm thuộc tính extraState nào vào JSON. Thao tác này giúp giảm kích thước tệp bạn lưu.

Dữ liệu sao lưu và chuyển đổi tuần tự đầy đủ

saveExtraState cũng nhận được một tham số doFullSerialization (không bắt buộc). Chiến dịch này được sử dụng bởi các khối tham chiếu trạng thái tham chiếu được chuyển đổi tuần tự bởi trình chuyển đổi tuần tự (như mô hình dữ liệu sao lưu). Thông số này báo hiệu rằng trạng thái được tham chiếu sẽ không có sẵn khi khối được giải tuần tự, vì vậy phải chuyển đổi tuần tự tất cả trạng thái sao lưu. Ví dụ: đây là true khi một khối riêng lẻ được chuyển đổi tuần tự hoặc khi một khối được sao chép và dán.

Có hai trường hợp sử dụng phổ biến cho vấn đề này:

  • Khi một khối riêng lẻ được tải vào một không gian làm việc nơi dữ liệu sao lưu mô hình này không tồn tại, mô hình này có đủ thông tin ở trạng thái riêng để để tạo một mô hình dữ liệu mới.
  • Khi được sao chép, một khối luôn tạo ra một bản sao lưu mới thay vì tham chiếu một mô hình dữ liệu hiện có.

Một số khối sử dụng lệnh này là @blockly/block-shareable-procedures. Bình thường chúng tuần tự hoá tham chiếu đến mô hình dữ liệu sao lưu. Mô hình này lưu trữ trạng thái của chúng. Tuy nhiên, nếu tham số doFullSerialization là true, thì chúng sẽ chuyển đổi tuần tự tất cả trạng thái của chúng. Các khối quy trình có thể chia sẻ sử dụng đoạn mã này để đảm bảo rằng khi chúng được sao chép và dán, chúng sẽ tạo một mô hình dữ liệu sao lưu mới, thay vì tham chiếu mô hình hiện tại.

mutationToDom và domToMutation

mutationToDomdomToMutation là các hook chuyển đổi tuần tự hoạt động với hệ thống chuyển đổi tuần tự XML cũ. Chỉ sử dụng những nội dung hấp dẫn này nếu cần (ví dụ: bạn hoạt động trên một cơ sở mã cũ chưa được di chuyển), nếu không, hãy sử dụng saveExtraStateloadExtraState.

mutationToDom trả về một nút XML đại diện cho trạng thái bổ sung của khối và domToMutation chấp nhận cùng một nút XML đó và áp dụng trạng thái cho khối.

// These are the old XML serialization hooks for the lists_create_with block.
mutationToDom: function() {
  // You *must* create a <mutation></mutation> element.
  // This element can have children.
  var container = Blockly.utils.xml.createElement('mutation');
  container.setAttribute('items', this.itemCount_);
  return container;
},

domToMutation: function(xmlElement) {
  this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
  // This is a helper function which adds or removes inputs from the block.
  this.updateShape_();
},

XML thu được sẽ có dạng như sau:

<block type="lists_create_with">
  <mutation items="3"></mutation>
</block>

Nếu hàm mutationToDom trả về giá trị rỗng, thì sẽ không có phần tử bổ sung nào được được thêm vào XML.

Hook giao diện người dùng

Nếu bạn cung cấp một số hàm nhất định như một phần của trình biến đổi, Blockly sẽ thêm "người biến đổi" mặc định Giao diện người dùng vào khối của bạn.

Bạn không cần phải sử dụng giao diện người dùng này nếu muốn thêm chuyển đổi tuần tự bổ sung. Bạn có thể sử dụng giao diện người dùng tuỳ chỉnh, như các khối-dấu cộng-trừ trình bổ trợ hoặc bạn có thể không sử dụng giao diện người dùng nào!

soạn và phân tách

Giao diện người dùng mặc định dựa trên các hàm composedecompose.

decompose "nổ" thành các khối con nhỏ hơn có thể được di chuyển xung quanh, đã thêm và bị xoá. Hàm này phải trả về một "khối trên cùng" tức là khối chính trong không gian làm việc của trình biến đổi mà các khối phụ kết nối.

Sau đó, compose sẽ diễn giải cấu hình của các khối phụ và sử dụng chúng để sửa đổi khối chính. Hàm này phải chấp nhận "khối trên cùng" đó là được decompose trả về dưới dạng tham số.

Lưu ý rằng các hàm này được "kết hợp" thành khối bị "thay đổi" nên this có thể được dùng để tham chiếu đến khối đó.

// These are the decompose and compose functions for the lists_create_with block.
decompose: function(workspace) {
  // This is a special sub-block that only gets created in the mutator UI.
  // It acts as our "top block"
  var topBlock = workspace.newBlock('lists_create_with_container');
  topBlock.initSvg();

  // Then we add one sub-block for each item in the list.
  var connection = topBlock.getInput('STACK').connection;
  for (var i = 0; i < this.itemCount_; i++) {
    var itemBlock = workspace.newBlock('lists_create_with_item');
    itemBlock.initSvg();
    connection.connect(itemBlock.previousConnection);
    connection = itemBlock.nextConnection;
  }

  // And finally we have to return the top-block.
  return topBlock;
},

// The container block is the top-block returned by decompose.
compose: function(topBlock) {
  // First we get the first sub-block (which represents an input on our main block).
  var itemBlock = topBlock.getInputTargetBlock('STACK');

  // Then we collect up all of the connections of on our main block that are
  // referenced by our sub-blocks.
  // This relates to the saveConnections hook (explained below).
  var connections = [];
  while (itemBlock && !itemBlock.isInsertionMarker()) {  // Ignore insertion markers!
    connections.push(itemBlock.valueConnection_);
    itemBlock = itemBlock.nextConnection &&
        itemBlock.nextConnection.targetBlock();
  }

  // Then we disconnect any children where the sub-block associated with that
  // child has been deleted/removed from the stack.
  for (var i = 0; i < this.itemCount_; i++) {
    var connection = this.getInput('ADD' + i).connection.targetConnection;
    if (connection && connections.indexOf(connection) == -1) {
      connection.disconnect();
    }
  }

  // Then we update the shape of our block (removing or adding iputs as necessary).
  // `this` refers to the main block.
  this.itemCount_ = connections.length;
  this.updateShape_();

  // And finally we reconnect any child blocks.
  for (var i = 0; i < this.itemCount_; i++) {
    connections[i].reconnect(this, 'ADD' + i);
  }
},

saveConnections

Nếu muốn, bạn cũng có thể xác định hàm saveConnections hoạt động với giao diện người dùng mặc định. Hàm này cho phép bạn liên kết các phần tử con của khối chính (tồn tại trên không gian làm việc chính) có các khối phụ tồn tại trong không gian làm việc của đối tượng biến đổi. Sau đó, bạn có thể dùng dữ liệu này để đảm bảo compose của mình sẽ kết nối lại các phần tử con của khối chính đúng cách khi các khối phụ được sắp xếp lại.

saveConnections phải chấp nhận "khối trên cùng" do decompose của bạn trả về dưới dạng tham số. Nếu hàm saveConnections được định nghĩa, thì Blockly sẽ gọi hàm này trước khi gọi compose.

saveConnections: function(topBlock) {
  // First we get the first sub-block (which represents an input on our main block).
  var itemBlock = topBlock.getInputTargetBlock('STACK');

  // Then we go through and assign references to connections on our main block
  // (input.connection.targetConnection) to properties on our sub blocks
  // (itemBlock.valueConnection_).
  var i = 0;
  while (itemBlock) {
    // `this` refers to the main block (which is being "mutated").
    var input = this.getInput('ADD' + i);
    // This is the important line of this function!
    itemBlock.valueConnection_ = input && input.connection.targetConnection;
    i++;
    itemBlock = itemBlock.nextConnection &&
        itemBlock.nextConnection.targetBlock();
  }
},

Đang đăng ký

Đột biến chỉ là một loại tiện ích mở rộng đặc biệt, do đó chúng cũng phải đã được đăng ký trước khi có thể sử dụng chúng trong tệp JSON của loại khối định nghĩa.

// Function signature.
Blockly.Extensions.registerMutator(name, mixinObj, opt_helperFn, opt_blockList);

// Example call.
Blockly.Extensions.registerMutator(
    'controls_if_mutator',
    { /* mutator methods */ },
    undefined,
    ['controls_if_elseif', 'controls_if_else']);
  • name: Một chuỗi liên kết với biến đổi để bạn có thể sử dụng trong JSON.
  • mixinObj: Một đối tượng chứa nhiều phương thức đột biến. Ví dụ: saveExtraStateloadExtraState.
  • opt_helperFn: Một hàm trợ giúp không bắt buộc sẽ chạy trên khối sau khi trộn.
  • opt_blockList: Một mảng các loại khối tuỳ chọn (dưới dạng chuỗi) sẽ được được thêm vào trình đơn hiển thị trong giao diện người dùng biến đổi mặc định, nếu các phương thức giao diện người dùng cũng xác định.

Lưu ý rằng không giống như tiện ích, mỗi loại khối có thể chỉ có một biến đổi.

{
  //...
  "mutator": "controls_if_mutator"
}

Chức năng trợ giúp

Cùng với Mixin, một biến đổi (mutator) có thể đăng ký một hàm trợ giúp. Chức năng này chạy trên mỗi khối thuộc loại đã cho sau khi được tạo và MixinObj được đã thêm. Nó có thể được dùng để thêm các yếu tố kích hoạt hoặc hiệu ứng khác vào một đột biến.

Ví dụ: bạn có thể thêm một trình trợ giúp vào khối giống như danh sách để thiết lập số mục ban đầu:

var helper = function() {
  this.itemCount_ = 5;
  this.updateShape();
}