Trường thả xuống

Trường thả xuống lưu trữ một chuỗi dưới dạng giá trị và một chuỗi làm văn bản. Chiến lược phát hành đĩa đơn là một khoá trung lập về ngôn ngữ sẽ được dùng để truy cập vào văn bản và sẽ không được dịch khi Blockly được chuyển đổi giữa các ngôn ngữ. Văn bản là một chuỗi mà con người đọc được. Chuỗi này sẽ được hiển thị cho người dùng.

dựa trên xu hướng

Hàm khởi tạo thả xuống lấy một trình tạo trình đơn và một thuộc tính không bắt buộc trình xác thực. Trình tạo thực đơn có rất nhiều tính linh hoạt nhưng về cơ bản là một dãy các lựa chọn, mỗi lựa chọn chứa phần mà con người có thể đọc được và một chuỗi trung lập về ngôn ngữ.

Trình đơn thả xuống chứa văn bản đơn giản

Mở trình đơn thả xuống có hai lựa chọn về văn bản

JSON

{
  "type": "example_dropdown",
  "message0": "drop down: %1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "FIELDNAME",
      "options": [
        [ "first item", "ITEM1" ],
        [ "second item", "ITEM2" ]
      ]
    }
  ]
}

JavaScript

Blockly.Blocks['example_dropdown'] = {
  init: function() {
    this.appendDummyInput()
        .appendField('drop down:')
        .appendField(new Blockly.FieldDropdown([
            ['first item', 'ITEM1'],
            ['second item', 'ITEM2']
        ]), 'FIELDNAME');
  }
};

Đảm bảo thông tin mà con người đọc được tách biệt với khoá trung lập về ngôn ngữ cho phép giữ nguyên chế độ cài đặt của trình đơn thả xuống giữa các ngôn ngữ. Cho phiên bản tiếng Anh của một khối có thể xác định [['left', 'LEFT'], ['right', 'RIGHT]] trong khi phiên bản tiếng Đức của cùng một khối sẽ xác định [['links', 'LEFT'], ['rechts', 'RIGHT]].

Trình đơn thả xuống hình ảnh

Các tuỳ chọn trong trình đơn thả xuống cũng có thể là hình ảnh thay vì văn bản. Các đối tượng hình ảnh được chỉ định với các thuộc tính src, width, heightalt.

Lưu ý rằng mặc dù trình đơn thả xuống có thể kết hợp các tuỳ chọn văn bản và hình ảnh, tuỳ chọn riêng lẻ hiện không thể chứa cả hình ảnh và văn bản.

Trường thả xuống chứa hình ảnh và văn bản

JSON

{
  "type": "image_dropdown",
  "message0": "flag %1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "FLAG",
      "options": [
        ["none", "NONE"],
        [{"src": "canada.png", "width": 50, "height": 25, "alt": "Canada"}, "CANADA"],
        [{"src": "usa.png", "width": 50, "height": 25, "alt": "USA"}, "USA"],
        [{"src": "mexico.png", "width": 50, "height": 25, "alt": "Mexico"}, "MEXICO"]
      ]
    }
  ]
}

JavaScript

Blockly.Blocks['image_dropdown'] = {
  init: function() {
    var input = this.appendDummyInput()
        .appendField('flag');
    var options = [
        ['none', 'NONE'],
        [{'src': 'canada.png', 'width': 50, 'height': 25, 'alt': 'Canada'}, 'CANADA'],
        [{'src': 'usa.png', 'width': 50, 'height': 25, 'alt': 'USA'}, 'USA'],
        [{'src': 'mexico.png', 'width': 50, 'height': 25, 'alt': 'Mexico'}, 'MEXICO']
    ];
    input.appendField(new Blockly.FieldDropdown(options), 'FLAG');
  }
};

Trình đơn thả xuống linh động

Trường thả xuống có các ngày trong tuần

JSON

{
  "type": "dynamic_dropdown",
  "message0": "day %1",
  "args0": [
    {
      "type": "input_dummy",
      "name": "INPUT"
    }
  ],
  "extensions": ["dynamic_menu_extension"]
}
Blockly.Extensions.register('dynamic_menu_extension',
  function() {
    this.getInput('INPUT')
      .appendField(new Blockly.FieldDropdown(
        function() {
          var options = [];
          var now = Date.now();
          for(var i = 0; i < 7; i++) {
            var dateString = String(new Date(now)).substring(0, 3);
            options.push([dateString, dateString.toUpperCase()]);
            now += 24 * 60 * 60 * 1000;
          }
          return options;
        }), 'DAY');
  });

Bạn có thể thực hiện việc này bằng cách sử dụng tệp JSON phần mở rộng.

JavaScript

Blockly.Blocks['dynamic_dropdown'] = {
  init: function() {
    var input = this.appendDummyInput()
      .appendField('day')
      .appendField(new Blockly.FieldDropdown(
        this.generateOptions), 'DAY');
  },

  generateOptions: function() {
    var options = [];
    var now = Date.now();
    for(var i = 0; i < 7; i++) {
      var dateString = String(new Date(now)).substring(0, 3);
      options.push([dateString, dateString.toUpperCase()]);
      now += 24 * 60 * 60 * 1000;
    }
    return options;
  }
};

Bạn cũng có thể cung cấp trình đơn thả xuống với một hàm thay vì danh sách tĩnh cho phép các tùy chọn có tính động. Hàm phải trả về một một mảng tuỳ chọn trong cùng một [human-readable-value, language-neutral-key] làm lựa chọn tĩnh. Mỗi lần người dùng nhấp vào trình đơn thả xuống, hàm này sẽ và tính toán lại các tuỳ chọn.

Chuyển đổi tuần tự

JSON

JSON cho trường thả xuống có dạng như sau:

{
  "fields": {
    "FIELDNAME": "LANGUAGE-NEUTRAL-KEY"
  }
}

Trong đó FIELDNAME là một chuỗi tham chiếu đến một trường thả xuống và giá trị là giá trị áp dụng cho trường. Giá trị phải là phím tuỳ chọn trung lập về ngôn ngữ.

XML

XML cho trường thả xuống sẽ có dạng như sau:

<field name="FIELDNAME">LANGUAGE-NEUTRAL-KEY</field>

Trong trường hợp thuộc tính name của trường chứa chuỗi tham chiếu đến một trình đơn thả xuống và văn bản bên trong là giá trị áp dụng cho trường này. Bên trong văn bản phải là một khoá tuỳ chọn trung lập về ngôn ngữ hợp lệ.

Tuỳ chỉnh

Bạn có thể sử dụng thuộc tính Blockly.FieldDropdown.ARROW_CHAR để thay đổi ký tự Unicode đại diện cho mũi tên thả xuống.

Trường thả xuống có mũi tên tuỳ chỉnh

Thuộc tính ARROW_CHAR mặc định là \u25BC (▼) trên Android và \u25BE (▾) nếu không.

Đây là thuộc tính toàn cầu, vì vậy thuộc tính này sẽ sửa đổi tất cả các trường thả xuống khi được đặt.

Bạn có thể dùng thuộc tính Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH để thay đổi chiều cao tối đa của trình đơn. Tỷ lệ này được định nghĩa là tỷ lệ phần trăm của khung nhìn chiều cao, khung nhìn là cửa sổ.

Thuộc tính MAX_MENU_HEIGHT_VH được đặt mặc định là 0,45.

Đây là thuộc tính toàn cầu, vì vậy thuộc tính này sẽ sửa đổi tất cả các trường thả xuống khi được đặt.

Khớp tiền tố/hậu tố

Nếu tất cả lựa chọn trên trình đơn thả xuống có chung tiền tố và/hoặc hậu tố các từ này sẽ tự động được loại trừ và được chèn dưới dạng văn bản tĩnh. Ví dụ: đây là 2 cách để tạo cùng một khối (trước tiên là khớp hậu tố và khớp thứ hai với):

Không có hậu tố khớp:

JSON

{
  "type": "dropdown_no_matching",
  "message0": "hello %1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "MODE",
      "options": [
        ["world", "WORLD"],
        ["computer", "CPU"]
      ]
    }
  ]
}

JavaScript

Blockly.Blocks['dropdown_no_matching'] = {
  init: function() {
    var options = [
      ['world', 'WORLD'],
      ['computer', 'CPU']
    ];

    this.appendDummyInput()
        .appendField('hello')
        .appendField(new Blockly.FieldDropdown(options), 'MODE');
  }
};

Có so khớp hậu tố:

JSON

{
  "type": "dropdown_with_matching",
  "message0": "%1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "MODE",
      "options": [
        ["hello world", "WORLD"],
        ["hello computer", "CPU"]
      ]
    }
  ]
}

JavaScript

Blockly.Blocks['dropdown_with_matching'] = {
  init: function() {
    var options = [
      ['hello world', 'WORLD'],
      ['hello computer', 'CPU']
    ];

    this.appendDummyInput()
        .appendField(new Blockly.FieldDropdown(options), 'MODE');
  }
};

Trường thả xuống với

Một ưu điểm của phương pháp này là việc khối dễ chuyển thành các ngôn ngữ khác. Mã trước đó có các chuỗi 'hello', 'world''computer', trong khi mã sửa đổi có các chuỗi 'hello world''hello computer'. Người dịch dịch các cụm từ dễ dàng hơn nhiều so với các từ một cách riêng biệt.

Một ưu điểm khác của phương pháp này là thứ tự từ thường thay đổi giữa ngôn ngữ. Hãy tưởng tượng một ngôn ngữ sử dụng 'world hello''computer hello'. Thuật toán so khớp hậu tố sẽ phát hiện 'hello' thông thường và hiển thị biến đó sau trình đơn thả xuống.

Tuy nhiên, đôi khi việc so khớp tiền tố/hậu tố không thành công. Có một số trường hợp mà hai từ phải luôn đi cùng nhau và không được bỏ tiền tố. Ví dụ: 'drive red car''drive red truck' chỉ nên được cho là chỉ nên đã loại bỏ 'drive', không phải 'drive red'. Mã không ngắt Unicode dấu cách '\u00A0' có thể được dùng thay cho dấu cách thông thường để loại bỏ bộ khớp tiền tố/hậu tố. Do đó, bạn có thể khắc phục ví dụ trên bằng 'drive red\u00A0car''drive red\u00A0truck'.

Một vị trí khác mà việc so khớp tiền tố/hậu tố không thành công là trong các ngôn ngữ không phân tách từng từ bằng dấu cách. Tiếng Trung là một ví dụ điển hình. Chuỗi '訪問中國' có nghĩa là 'visit China'. Xin lưu ý rằng bạn không thể dùng khoảng trắng giữa các từ. Hai ký tự cuối cùng ('中國') là từ của 'China', nhưng nếu phân tách, chúng sẽ có nghĩa là 'centre''country' tương ứng. Để thực hiện kết hợp tiền tố/hậu tố trong các ngôn ngữ như tiếng Trung, bạn chỉ cần chèn dấu cách vào vị trí cần ngắt. Ví dụ: '訪問 中國''訪問 美國' sẽ dẫn đến "visit [China/USA]", trong khi '訪問 中 國''訪問 美 國' sẽ dẫn đến "visit [centre/beautiful] country".

Tạo trình xác thực trình đơn thả xuống

Giá trị của trường thả xuống là một chuỗi trung lập về ngôn ngữ, do đó mọi trình xác thực đều phải chấp nhận một chuỗi và trả về một chuỗi là một phương án có sẵn, null hoặc undefined.

Nếu trình xác thực của bạn trả về thông tin khác, thì hành vi của Blockly là chưa xác định và mà chương trình của bạn có thể gặp sự cố.

Ví dụ: bạn có thể xác định một trường thả xuống có 3 lựa chọn và như sau:

validate: function(newValue) {
  this.getSourceBlock().updateConnections(newValue);
  return newValue;
},

init: function() {
  var options = [
   ['has neither', 'NEITHER'],
   ['has statement', 'STATEMENT'],
   ['has value', 'VALUE'],
  ];

  this.appendDummyInput()
  // Pass the field constructor the options list, the validator, and the name.
      .appendField(new Blockly.FieldDropdown(options, this.validate), 'MODE');
}

validate luôn trả về giá trị đã truyền nhưng sẽ gọi trình trợ giúp hàm updateConnection thêm hoặc loại bỏ dữ liệu đầu vào dựa trên trình đơn thả xuống giá trị:

updateConnections: function(newValue) {
  this.removeInput('STATEMENT', /* no error */ true);
  this.removeInput('VALUE', /* no error */ true);
  if (newValue == 'STATEMENT') {
    this.appendStatementInput('STATEMENT');
  } else if (newValue == 'VALUE') {
    this.appendValueInput('VALUE');
  }
}