שדות נפתחים

השדה הנפתח שומר מחרוזת בתור הערך שלה ומחרוזת בתור הטקסט שלה. הערך הוא מפתח נייטרלי, שישמש לגישה לטקסט, ולא יתורגם כשעוברים בין שפות ב-Blockly. הטקסט הוא מחרוזת שתוצג למשתמש, שאנשים יכולים לקרוא.

יצירה

המבנה של התפריט הנפתח מקבל מחולל תפריטים וvalidator אופציונלי. מחולל התפריטים כולל הרבה גמישות, אבל למעשה הוא כולל מערך של אפשרויות, שכל אחת מהן מכילה חלק שקריא לבני אדם ומחרוזת נייטרלית משפה.

תפריטים נפתחים פשוטים של טקסט

פתיחת תפריט נפתח עם שתי אפשרויות טקסט

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');
  }
};

אם מפרידים בין המידע הקריא לבני אדם מהמקש הנייטרלי, ההגדרה של התפריט הנפתח נשמרת בין השפות. במקרה כזה, גרסה באנגלית של בלוק יכולה להגדיר את [['left', 'LEFT'], ['right', 'RIGHT]], ואילו גרסה גרמנית של אותו בלוק תגדיר את [['links', 'LEFT'], ['rechts', 'RIGHT]].

תפריטים נפתחים של תמונות

האפשרויות בתפריט הנפתח יכולות להיות גם תמונות במקום טקסט. אובייקטים של תמונות מצוינים באמצעות המאפיינים src, width, height ו-alt.

שימו לב: תפריט נפתח יכול לכלול שילוב של אפשרויות טקסט ואפשרויות תמונה, אבל בשלב זה אפשרות מסוימת לא יכולה לכלול גם תמונה וגם טקסט.

שדה נפתח שמכיל תמונות וטקסט

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');
  }
};

תפריטים נפתחים דינמיים

שדה נפתח עם הימים בשבוע

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');
  });

הפעולה הזו מתבצעת באמצעות תוסף JSON.

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;
  }
};

אפשר גם להוסיף תפריט נפתח עם פונקציה במקום רשימה של אפשרויות סטטיות, וכך האפשרויות להיות דינמיות. הפונקציה צריכה להחזיר מערך של אפשרויות באותו פורמט [human-readable-value, language-neutral-key] של אפשרויות סטטיות. בכל פעם שלוחצים על התפריט הנפתח, הפונקציה רצה והאפשרויות מחושבות מחדש.

עריכה טורית

JSON

ה-JSON של שדה נפתח נראה כך:

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

כאשר FIELDNAME הוא מחרוזת שמפנה לשדה נפתח, והערך הוא הערך שיש להחיל על השדה. הערך צריך להיות מפתח אפשרות נייטרלי לשפה.

XML

ה-XML של שדה נפתח נראה כך:

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

כאשר המאפיין name של השדה מכיל מחרוזת שמפנה לשדה תפריט נפתח, והטקסט הפנימי הוא הערך שצריך להחיל על השדה. הטקסט הפנימי צריך להיות מפתח אפשרות נייטרלי חוקי.

התאמה אישית

ניתן להשתמש במאפיין Blockly.FieldDropdown.ARROW_CHAR כדי לשנות את תו ה-Unicode שמייצג את החץ בתפריט הנפתח.

שדה נפתח עם חץ בהתאמה אישית

ברירת המחדל של המאפיין ARROW_CHAR היא \u25BC (▼) ב-Android ו-\u25BE (נשלחה) אחרת.

זהו נכס גלובלי, לכן הוא ישנה את כל השדות הנפתחים לאחר הגדרתו.

אפשר להשתמש במאפיין Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH כדי לשנות את הגובה המקסימלי של התפריט. הוא מוגדר כאחוז מגובה אזור התצוגה, כאשר אזור התצוגה הוא החלון.

ערך ברירת המחדל של המאפיין MAX_MENU_HEIGHT_VH הוא 0.45.

זהו נכס גלובלי, לכן הוא ישנה את כל השדות הנפתחים לאחר הגדרתו.

התאמת קידומת/סיומת

אם לכל האפשרויות בתפריט הנפתח יש מילות קידומת ו/או סיומת משותפות, המילים האלה יושמטו באופן אוטומטי ויוכנסו כטקסט סטטי. לדוגמה, יש שתי דרכים ליצור את אותו הבלוק (הראשונה ללא התאמת סיומת, והשנייה עם):

ללא התאמת סיומות:

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');
  }
};

בעזרת התאמת סיומות:

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');
  }
};

שדה נפתח עם

אחד היתרונות של הגישה הזו הוא שקל יותר לתרגם את החסימה לשפות אחרות. הקוד הקודם כולל את המחרוזות 'hello', 'world' ו-'computer', ואילו הקוד המתוקן כולל את המחרוזות 'hello world' ו-'hello computer'. למתרגמים קל יותר לתרגם ביטויים ממילים בנפרד.

יתרון נוסף של הגישה הזו הוא שסדר המילים משתנה לעיתים קרובות בין שפות. תארו לעצמכם שפה שבה משתמשים ב-'world hello' וב-'computer hello'. אלגוריתם ההתאמה של הסיומת יזהה את 'hello' הנפוץ ויציג אותו אחרי התפריט הנפתח.

עם זאת, לפעמים ההתאמה של התחילית/סיומת נכשלת. במקרים מסוימים, שתי מילים תמיד צריכות להופיע יחד ואין לכלול את הקידומת. לדוגמה, אפשר להסיק שהחישוב של 'drive red car' ושל 'drive red truck' כולל רק 'drive', ולא 'drive red'. אפשר להשתמש ברווח '\u00A0' מסוג Unicode שאינו נשבר, במקום ברווח רגיל, כדי להשמיט את התו להתאמה של הקידומת/הסיומת. לכן אפשר לתקן את הדוגמה שלמעלה באמצעות 'drive red\u00A0car' ו-'drive red\u00A0truck'.

מקום נוסף שבו התאמת קידומת/סיומת נכשלת הוא בשפות שלא מפרידות מילים בודדות באמצעות רווחים. דוגמה טובה לכך היא סינית. המחרוזת '訪問中國' פירושה 'visit China'. חשוב לשים לב שאין רווחים בין המילים. יחד, שני התווים האחרונים ('中國') הם המילה של 'China', אבל אם הם יפוצלו, המשמעות שלהם היא 'centre' ו-'country' בהתאמה. כדי שהתאמת קידומת/סיומת תפעל בשפות כמו סינית, פשוט מוסיפים רווח במקום שבו אמורה להופיע ההפסקה. לדוגמה, הקוד '訪問 中國' ו-'訪問 美國' יגרמו ל-"visit [China/USA]", בעוד ש-'訪問 中 國' ו-'訪問 美 國' יגרמו ל-"visit [centre/beautiful] country".

יצירת תפריט נפתח לאימות

הערך בשדה של תפריט נפתח הוא מחרוזת נייטרלית, ולכן כל האימות צריך לקבל מחרוזת ולהחזיר מחרוזת שזמינה, null או undefined.

אם כלי התיקוף מחזיר מידע אחר, ההתנהגות שלBlockly לא מוגדרת והתוכנית עלולה לקרוס.

לדוגמה, אפשר להגדיר שדה נפתח עם 3 אפשרויות וכלי תיקוף כמו:

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 תמיד מחזירה את הערך שהיא הועברה, אבל היא קוראת לפונקציית המסייע updateConnection, שמוסיפה או מסירה קלט על סמך הערך בתפריט הנפתח:

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');
  }
}