إنشاء نوع حقل جديد

قبل إنشاء نوع حقل جديد، ضع في اعتبارك ما إذا كانت إحدى الطرق الأخرى لتخصيص الحقول تناسب احتياجاتك. إذا كان تطبيقك يحتاج إلى تخزين نوع قيمة جديد، أو كنت تريد إنشاء واجهة مستخدم جديدة لنوع قيمة حالي، قد تحتاج إلى إنشاء نوع حقل جديد.

لإنشاء حقل جديد، يُرجى اتّباع الخطوات التالية:

  1. تنفيذ دالة إنشائية.
  2. سجِّل مفتاح JSON ونفِّذ fromJson.
  3. التعامل مع إعداد واجهة المستخدم المضمّنة في الحظر والمُستمعون إلى الأحداث:
  4. التعامل مع أدوات معالجة الأحداث (يتم التعامل مع التخلص من واجهة المستخدم من أجلك)
  5. تنفيذ معالجة القيمة:
  6. أضِف تمثيلاً نصيًا لقيمة الحقل لتسهيل الاستخدام.
  7. يمكنك إضافة وظائف أخرى، مثل:
  8. اضبط جوانب إضافية للحقل، مثل:

يفترض هذا القسم أنك قد قرأت محتوى تحليل أحد الحقول، وأنك على دراية به.

للحصول على مثال لحقل مخصّص، اطّلِع على العرض التوضيحي للحقول المخصّصة .

تنفيذ دالة إنشائية

تكون الدالة الإنشائية للحقل مسؤولة عن إعداد القيمة الأولية للحقل وإعداد أداة تحقّق محلية اختياريًا. ويتم استدعاء الدالة الإنشائية للحقل المخصّص أثناء إعداد كتلة المصدر بغض النظر عمّا إذا كان قد تم تحديد كتلة المصدر بتنسيق JSON أو JavaScript. لذلك، لا يمكن للحقل المخصص الوصول إلى كتلة المصدر أثناء البناء.

يعمل نموذج الرمز البرمجي التالي على إنشاء حقل مخصّص باسم GenericField:

class GenericField extends Blockly.Field {
  constructor(value, validator) {
    super(value, validator);

    this.SERIALIZABLE = true;
  }
}

توقيع الطريقة

عادةً ما تستخدم منصات إنشاء الحقل قيمة ومدققًا محليًا. تكون القيمة اختيارية، وإذا لم تمرر قيمة (أو مررت قيمة لم تنجح في التحقق من الفئة)، فسيتم استخدام القيمة الافتراضية للفئة الفائقة. بالنسبة إلى فئة Field التلقائية، تكون هذه القيمة هي null. إذا كنت لا تريد هذه القيمة الافتراضية، فتأكد من تمرير قيمة مناسبة. تتوفّر معلمة أداة التحقق من الصحة فقط للحقول القابلة للتعديل وعادةً ما تحمل علامة اختيارية. تعرَّف على مزيد من المعلومات حول أدوات التحقق في مستندات أدوات التحقق من الصحة.

البنية

يجب أن يتبع المنطق داخل الدالة الإنشائية هذا التدفق:

  1. استدعِ دالة الإنشاء الفائقة الموروثة (يجب أن تكتسب جميع الحقول المخصّصة من Blockly.Field أو إحدى فئاتها الفرعية) لضبط القيمة بشكلٍ صحيح وضبط أداة التحقّق المحلية للحقل.
  2. إذا كان الحقل قابلاً للتسلسل، فقم بتعيين الخاصية المقابلة في الدالة الإنشائية. يجب أن تكون الحقول القابلة للتعديل قابلة للتسلسل، والحقول قابلة للتعديل بشكل تلقائي، لذا يجب ضبط هذه الخاصية على "صحيح" إلا إذا كنت تعرف أنّها غير قابلة للتسلسل.
  3. اختياري: طبِّق تخصيصًا إضافيًا (على سبيل المثال، تسمح حقول التصنيف بتمرير فئة css، والتي يتمّ تطبيقها بعد ذلك على النص).

JSON والتسجيل

في تعريفات مجموعات JSON، يتم وصف الحقول بسلسلة (مثل field_number وfield_textinput). يحتفظ بشكل حظر بخريطة من هذه السلاسل لكائنات الحقول ويستدعي fromJson للكائن المناسب أثناء الإنشاء.

استدعِ Blockly.fieldRegistry.register لإضافة نوع الحقل إلى هذه الخريطة، مع تمرير فئة الحقل كوسيطة ثانية:

Blockly.fieldRegistry.register('field_generic', GenericField);

يجب أيضًا تعريف الدالة fromJson. يجب أن تشير عملية التنفيذ أولاً إلى أي مراجع string table باستخدام replaceMessageReferences، ثم تمرير القيم إلى الدالة الإنشائية.

GenericField.fromJson = function(options) {
  const value = Blockly.utils.parsing.replaceMessageReferences(
      options['value']);
  return new CustomFields.GenericField(value);
};

جارٍ الإعداد

عند إنشاء الحقل، يحتوي في الأساس على قيمة فقط. الإعداد هو المكان الذي يتم فيه إنشاء DOM، ويتم إنشاء النموذج (إذا كان الحقل يحتوي على نموذج)، ويتم ربط الأحداث.

شاشة العرض القابلة للحظر

أثناء الإعداد، ستكون مسؤولاً عن إنشاء أي شيء ستحتاجه لعرض الميدان في الحظر.

الإعدادات التلقائية والخلفية والنص

تنشئ دالة initView التلقائية عنصر rect بلون فاتح وعنصر text. إذا أردت أن يحتوي حقلك على كلا العنصرَين، بالإضافة إلى بعض المزايا الإضافية، استدع الدالة initView الفائقة قبل إضافة بقية عناصر DOM. إذا كنت تريد أن يحتوي الحقل على أحد هذين العنصرَين وليس كليهما، يمكنك استخدام الدالتَين createBorderRect_ أو createTextElement_.

تخصيص إنشاء DOM

إذا كان حقلك عبارة عن حقل نصي عام (على سبيل المثال، إدخال نص)، سيتم التعامل مع إنشاء نموذج كائن المستند (DOM) نيابةً عنك. وإلا ستحتاج إلى إلغاء الدالة initView لإنشاء عناصر DOM التي ستحتاجها أثناء العرض المستقبلي للحقل.

على سبيل المثال، قد يحتوي حقل القائمة المنسدلة على كل من الصور والنص. في initView، يتم إنشاء عنصر صورة واحد وعنصر نصي واحد. خلال render_، يتم عرض العنصر النشط وإخفاء العنصر الآخر استنادًا إلى نوع الخيار المحدَّد.

يمكن إنشاء عناصر DOM باستخدام طريقة Blockly.utils.dom.createSvgElement أو أساليب إنشاء DOM التقليدية.

متطلبات عرض الحقل في الحظر هي:

  • يجب أن تكون جميع عناصر DOM عناصر ثانوية للحقل fieldGroup_. يتم إنشاء مجموعة الحقول تلقائيًا.
  • يجب أن تظل جميع عناصر DOM داخل أبعاد الحقل التي تم الإبلاغ عنها.

راجع قسم العرض للحصول على مزيد من التفاصيل حول تخصيص وتعديل العرض في الحظر.

إضافة رموز نصية

إذا أردت إضافة رموز إلى نص حقل (مثل رمز درجة الزاوية)، يمكنك إلحاق عنصر الرمز (عادةً ما يكون في <tspan>) مباشرةً بالحقل textElement_.

أحداث الإدخال

تسجّل الحقول التلقائية أحداث التلميحات وأحداث النقر على الماوس (سيتم استخدامها لعرض المحررين). إذا كنت تريد الاستماع إلى أنواع أخرى من الأحداث (على سبيل المثال، إذا كنت تريد التعامل مع السحب في حقل)، يجب إلغاء دالة bindEvents_ للحقل.

bindEvents_() {
  // Call the superclass function to preserve the default behavior as well.
  super.bindEvents_();

  // Then register your own additional event listeners.
  this.mouseDownWrapper_ =
  Blockly.browserEvents.conditionalBind(this.getClickTarget_(), 'mousedown', this,
      function(event) {
        this.originalMouseX_ = event.clientX;
        this.isMouseDown_ = true;
        this.originalValue_ = this.getValue();
        event.stopPropagation();
      }
  );
  this.mouseMoveWrapper_ =
    Blockly.browserEvents.conditionalBind(document, 'mousemove', this,
      function(event) {
        if (!this.isMouseDown_) {
          return;
        }
        var delta = event.clientX - this.originalMouseX_;
        this.setValue(this.originalValue_ + delta);
      }
  );
  this.mouseUpWrapper_ =
    Blockly.browserEvents.conditionalBind(document, 'mouseup', this,
      function(_event) {
        this.isMouseDown_ = false;
      }
  );
}

للربط بحدث، يجب بشكل عام استخدام الدالة Blockly.utils.browserEvents.conditionalBind. تعمل طريقة ربط الأحداث هذه على تصفية اللمسات الثانوية أثناء المسودة. إذا كنت تريد أن يتم تشغيل المعالج حتى في منتصف عملية سحب جارية، يمكنك استخدام الدالة Blockly.browserEvents.bind.

التخلص من المنتج

إذا سجّلت أي أدوات معالجة للأحداث المخصّصة داخل دالة bindEvents_ للحقل، يجب إلغاء تسجيلها داخل دالة dispose.

في حال إعداد عرض الحقل بشكل صحيح (من خلال إلحاق جميع عناصر DOM بـ fieldGroup_)، سيتم التخلص من نموذج العناصر في المستند (DOM) للحقل تلقائيًا.

التعامل مع القيمة

← للحصول على معلومات حول قيمة الحقل مقارنةً بنصه، راجع بنية الحقل.

طلب التحقق من الصحة

رسم بياني انسيابي يصف ترتيب تشغيل أدوات التحقق

تنفيذ مدقّق الفئة

يجب أن تقبل الحقول قيمًا معيّنة فقط. على سبيل المثال، يجب أن تقبل حقول الأرقام الأرقام فقط، ويجب أن تقبل حقول الألوان الألوان فقط وما إلى ذلك، ويتم ضمان ذلك من خلال الصفوف وأدوات التحقق المحلية. تتّبع أداة التحقق من الفئة القواعد نفسها المتّبعة في أدوات التحقق المحلية، باستثناء أنه يتم تشغيلها أيضًا في أداة الإنشاء، وبالتالي يجب ألا تشير إلى مجموعة المصدر.

لتنفيذ أداة التحقق من الفئة في حقلك، عليك إلغاء الدالة doClassValidation_.

doClassValidation_(newValue) {
  if (typeof newValue != 'string') {
    return null;
  }
  return newValue;
};

التعامل مع القيم الصالحة

إذا كانت القيمة التي تم تمريرها إلى حقل يحتوي على setValue صالحة، ستتلقّى رد اتصال doValueUpdate_. تعمل الدالة doValueUpdate_ تلقائيًا على النحو التالي:

  • تضبط السمة value_ على newValue.
  • تضبط السمة isDirty_ على true.

وإذا كنت تحتاج ببساطة إلى تخزين القيمة ولا تريد إجراء أي معالجة مخصّصة، لن تحتاج إلى إلغاء doValueUpdate_.

وبخلاف ذلك، إذا كنت تريد تنفيذ إجراءات مثل:

  • مساحة تخزين مخصّصة تبلغ newValue.
  • تغيير المواقع الأخرى استنادًا إلى newValue.
  • احفظ ما إذا كانت القيمة الحالية صالحة أم لا.

يجب إلغاء doValueUpdate_:

doValueUpdate_(newValue) {
  super.doValueUpdate_(newValue);
  this.displayValue_ = newValue;
  this.isValueValid_ = true;
}

معالجة القيم غير الصالحة

إذا كانت القيمة التي تم تمريرها إلى الحقل مع setValue غير صالحة، ستتلقّى رد اتصال doValueInvalid_. ولا تفعل دالة doValueInvalid_ أي شيء تلقائيًا. وهذا يعني أنه لن تظهر القيم غير الصالحة تلقائيًا. ويعني ذلك أيضًا عدم عرض الحقل، لأنّه لن يتم ضبط السمة isDirty_.

إذا أردت عرض قيم غير صالحة، يجب إلغاء السمة doValueInvalid_. في معظم الحالات، يجب ضبط سمة displayValue_ على قيمة غير صالحة وضبط سمة isDirty_ على true وإلغاء العرض_ لكي يتم تعديل العرض ضمن الحظر استنادًا إلى السمة displayValue_ بدلاً من السمة value_.

doValueInvalid_(newValue) {
  this.displayValue_ = newValue;
  this.isDirty_ = true;
  this.isValueValid_ = false;
}

قيم متعدّدة الأجزاء

عندما يحتوي الحقل على قيمة متعددة الأجزاء (على سبيل المثال، القوائم والمتجهات والكائنات)، فقد ترغب في التعامل مع الأجزاء كقيم فردية.

doClassValidation_(newValue) {
  if (FieldTurtle.PATTERNS.indexOf(newValue.pattern) == -1) {
    newValue.pattern = null;
  }

  if (FieldTurtle.HATS.indexOf(newValue.hat) == -1) {
    newValue.hat = null;
  }

  if (FieldTurtle.NAMES.indexOf(newValue.turtleName) == -1) {
    newValue.turtleName = null;
  }

  if (!newValue.pattern || !newValue.hat || !newValue.turtleName) {
    this.cachedValidatedValue_ = newValue;
    return null;
  }
  return newValue;
}

في المثال أعلاه، يتم التحقّق من صحة كل موقع من سمات newValue بشكل فردي. وبعد ذلك، في نهاية دالة doClassValidation_، إذا كانت أي سمة فردية غير صالحة، يتم تخزين القيمة مؤقتًا في السمة cacheValidatedValue_ قبل عرض null (غير صالحة). إنّ التخزين المؤقت للكائن باستخدام سمات تم التحقّق من صحتها بشكل فردي يسمح لدالة doValueInvalid_ بالتعامل معها بشكل منفصل عن طريق إجراء فحص !this.cacheValidatedValue_.property بدلاً من إعادة التحقّق من كل سمة على حدة.

يمكن أيضًا استخدام هذا النمط للتحقق من صحة القيم متعددة الأجزاء في أدوات التحقق المحلية ولكن لا تتوفر حاليًا طريقة لفرض هذا النمط.

isDirty_

isDirty_ هي علامة تستخدم في دالة setValue، بالإضافة إلى أجزاء أخرى من الحقل، لمعرفة ما إذا كان الحقل بحاجة إلى إعادة العرض. في حال تغيير قيمة عرض الحقل، يجب عادةً ضبط isDirty_ على true.

النص

← للحصول على معلومات عن مكان استخدام نص الحقل ومدى اختلافه عن قيمة الحقل، راجع تحليل بنية الحقل.

إذا كان نص الحقل مختلفًا عن قيمة الحقل، عليك إلغاء الدالة getText لتوفير النص الصحيح.

getText() {
  let text = this.value_.turtleName + ' wearing a ' + this.value_.hat;
  if (this.value_.hat == 'Stovepipe' || this.value_.hat == 'Propeller') {
    text += ' hat';
  }
  return text;
}

إنشاء محرِّر

إذا حدّدت الدالة showEditor_، سيستمع بشكل تلقائي حظر الإعلانات إلى النقرات واستدعاء showEditor_ في الوقت المناسب. يمكنك عرض أي ترميز HTML في المحرر من خلال إحاطته بأحد عنصري div الخاصين، يطلق عليهما DropDownDiv وWidgetDiv، واللذين يطفوان فوق بقية واجهة مستخدم Bluely.

يتم استخدام DropDownDiv لتوفير المحررين الذين يتواجدون داخل مربع متصل بحقل. يقوم تلقائيًا بوضع نفسه ليكون بالقرب من الحقل مع البقاء ضمن الحدود المرئية. منتقي الزوايا وأداة اختيار الألوان هما مثالان جيدان على السمة DropDownDiv.

صورة لأداة اختيار الزوايا

يتم استخدام WidgetDiv لتوفير أدوات تحرير لا تكون داخل صندوق. تستخدم حقول الأرقام WidgetDiv لتغطية الحقل بمربع إدخال نص HTML. بينما تتعامل أداة DropDownDiv مع تحديد الموضع نيابةً عنك، لا تتعامل أداة WidgetDiv مع هذا الموضع. يجب وضع العناصر يدويًا. يوجد نظام الإحداثيات في إحداثيات البكسل بالنسبة إلى الجزء العلوي الأيسر من النافذة. ويُعدّ محرّر إدخال النص مثالاً جيدًا على WidgetDiv.

صورة محرِّر إدخال النص

showEditor_() {
  // Create the widget HTML
  this.editor_ = this.dropdownCreate_();
  Blockly.DropDownDiv.getContentDiv().appendChild(this.editor_);

  // Set the dropdown's background colour.
  // This can be used to make it match the colour of the field.
  Blockly.DropDownDiv.setColour('white', 'silver');

  // Show it next to the field. Always pass a dispose function.
  Blockly.DropDownDiv.showPositionedByField(
      this, this.disposeWidget_.bind(this));
}

نموذج رمز WidgetDiv

showEditor_() {
  // Show the div. This automatically closes the dropdown if it is open.
  // Always pass a dispose function.
  Blockly.WidgetDiv.show(
    this, this.sourceBlock_.RTL, this.widgetDispose_.bind(this));

  // Create the widget HTML.
  var widget = this.createWidget_();
  Blockly.WidgetDiv.getDiv().appendChild(widget);
}

جارٍ التنظيف

يؤدي كل من DropDownDiv وأداة WidgetDiv إلى إتلاف عناصر HTML للأداة، ولكنك تحتاج إلى التخلص يدويًا من أي أدوات معالجة أحداث طبقتها على تلك العناصر.

widgetDispose_() {
  for (let i = this.editorListeners_.length, listener;
      listener = this.editorListeners_[i]; i--) {
    Blockly.browserEvents.unbind(listener);
    this.editorListeners_.pop();
  }
}

يتم استدعاء الدالة dispose في سياق null في DropDownDiv. وفي WidgetDiv، يتم استدعائها في سياق WidgetDiv. في كلتا الحالتين، من الأفضل استخدام دالة bind عند تمرير دالة التخلص، كما هو موضّح في المثالين التاليين DropDownDiv وWidgetDiv أعلاه.

← للحصول على معلومات حول التخلص من المحتوى لا يقتصر على التخلص من أدوات التحرير، يُرجى الاطّلاع على القسم التخلص من المحتوى.

تحديث شاشة العرض في الحظر

تُستخدَم الدالة render_ لتعديل عرض الحقل ضمن الحظر لمطابقة قيمته الداخلية.

تشمل الأمثلة الشائعة ما يلي:

  • تغيير النص (قائمة منسدلة)
  • تغيير اللون (اللون)

الإعدادات التلقائية

تضبط دالة render_ التلقائية النص المعروض على نتيجة دالة getDisplayText_. تعرض الدالة getDisplayText_ سمة value_ الخاصة بالحقل التي يتم إرسالها إلى سلسلة بعد اقتطاعها لمراعاة الحد الأقصى لطول النص.

إذا كنت تستخدم طريقة العرض التلقائية لحظر المحتوى وكان السلوك التلقائي للنص متوافقًا مع الحقل، لن تحتاج إلى إلغاء render_.

إذا كان السلوك التلقائي للنص متاحًا في الحقل الخاص بك، وكانت عرض الحقل ضمن الحظر يحتوي على عناصر ثابتة إضافية، يمكنك استدعاء الدالة render_ التلقائية، ولكن سيظل عليك تجاوزها من أجل تعديل حجم الحقل.

إذا كان السلوك التلقائي للنص لا يتناسب مع حقلك أو إذا كان عرض الحقل في الحظر يتضمن عناصر ديناميكية إضافية، ستحتاج إلى تخصيص الوظيفة render_.

مخطط انسيابي يصف كيفية اتخاذ قرار بشأن تجاوز العرض_

تخصيص العرض

إذا كان سلوك العرض التلقائي لا يعمل مع حقلك، ستحتاج إلى تحديد سلوك العرض المخصَّص. وقد يشمل ذلك أي شيء بدءًا من تعيين نص عرض مخصص، إلى تغيير عناصر الصورة، إلى تحديث ألوان الخلفية.

جميع التغييرات في سمات DOM قانونية، الشيء الوحيد الذي يجب تذكره هما:

  1. يجب التعامل مع إنشاء نموذج العناصر في المستند (DOM) أثناء الإعداد لأنه أكثر كفاءة.
  2. يجب دائمًا تعديل السمة size_ لتتطابق مع حجم الشاشة ضمن الحظر.
render_() {
  switch(this.value_.hat) {
    case 'Stovepipe':
      this.stovepipe_.style.display = '';
      break;
    case 'Crown':
      this.crown_.style.display = '';
      break;
    case 'Mask':
      this.mask_.style.display = '';
      break;
    case 'Propeller':
      this.propeller_.style.display = '';
      break;
    case 'Fedora':
      this.fedora_.style.display = '';
      break;
  }

  switch(this.value_.pattern) {
    case 'Dots':
      this.shellPattern_.setAttribute('fill', 'url(#polkadots)');
      break;
    case 'Stripes':
      this.shellPattern_.setAttribute('fill', 'url(#stripes)');
      break;
    case 'Hexagons':
      this.shellPattern_.setAttribute('fill', 'url(#hexagons)');
      break;
  }

  this.textContent_.nodeValue = this.value_.turtleName;

  this.updateSize_();
}

جارٍ تعديل الحجم

يُعدّ تعديل السمة size_ للحقل أمرًا مهمًا جدًا، لأنّه يُطلع رمز عرض الحظر بكيفية وضع الحقل. إنّ أفضل طريقة لمعرفة ما يجب أن تكون عليه size_ بالضبط هي من خلال التجربة.

updateSize_() {
  const bbox = this.movableGroup_.getBBox();
  let width = bbox.width;
  let height = bbox.height;
  if (this.borderRect_) {
    width += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
    height += this.constants_.FIELD_BORDER_RECT_X_PADDING * 2;
    this.borderRect_.setAttribute('width', width);
    this.borderRect_.setAttribute('height', height);
  }
  // Note how both the width and the height can be dynamic.
  this.size_.width = width;
  this.size_.height = height;
}

ألوان القوالب المتطابقة

وإذا أردت أن تتطابق عناصر حقلك مع ألوان المربّع المرفقة بها، عليك إلغاء طريقة applyColour. سترغب في الوصول إلى اللون من خلال خاصية نمط الكتلة.

applyColour() {
  const sourceBlock = this.sourceBlock_;
  if (sourceBlock.isShadow()) {
    this.arrow_.style.fill = sourceBlock.style.colourSecondary;
  } else {
    this.arrow_.style.fill = sourceBlock.style.colourPrimary;
  }
}

جارٍ تحديث إمكانية التعديل

يمكن استخدام الدالة updateEditable لتغيير كيفية ظهور الحقل بناءً على ما إذا كان قابلاً للتعديل أم لا. تجعل الدالة الافتراضية الأمر بحيث لا تحتوي الخلفية على استجابة تمرير (حدود) إذا كانت قابلة للتعديل أو غير قابلة للتعديل. من المفترض ألا يتغير حجم شاشة العرض في الحظر وفقًا لإمكانية تعديلها، ولكن يُسمح بجميع التغييرات الأخرى.

updateEditable() {
  if (!this.fieldGroup_) {
    // Not initialized yet.
    return;
  }
  super.updateEditable();

  const group = this.getClickTarget_();
  if (!this.isCurrentlyEditable()) {
    group.style.cursor = 'not-allowed';
  } else {
    group.style.cursor = this.CURSOR;
  }
}

التسلسل

يدور التسلسل حول حفظ حالة الحقل بحيث يمكن إعادة تحميله في مساحة العمل لاحقًا.

تتضمن حالة مساحة العمل دائمًا قيمة الحقل، ولكن يمكن أن تتضمن أيضًا حالة أخرى، مثل حالة واجهة مستخدم الحقل. على سبيل المثال، إذا كان الحقل عبارة عن خريطة قابلة للتكبير/التصغير تسمح للمستخدم بتحديد البلدان، فيمكنك أيضًا تسلسل مستوى التكبير/التصغير.

إذا كان الحقل قابلاً للتسلسل، يجب ضبط السمة SERIALIZABLE على true.

يوفر بشكل أساسي مجموعتَين من عناصر الجذب للتسلسل. يعمل أحدهما مع نظام تسلسل JSON الجديد، بينما يعمل الزوج الآخر مع نظام تسلسل XML القديم.

saveState وloadState

saveState وloadState هما أداتان للتسلسل الذي يعمل مع نظام تسلسل JSON الجديد.

وفي بعض الحالات، لا تحتاج إلى تقديم هذه التفاصيل؛ لأن عمليات التنفيذ الافتراضية ستعمل. إذا كان (1) الحقل الخاص بك عبارة عن فئة فرعية مباشرة من فئة Blockly.Field الأساسية، (2) كانت القيمة من نوع JSON القابل للتسلسل، و (3) ما عليك سوى إنشاء تسلسل للقيمة، سيعمل التنفيذ التلقائي على النحو المطلوب.

بخلاف ذلك، يجب أن تعرض الدالة saveState كائن/قيمة JSON متسلسلة والذي يمثل حالة الحقل. ويجب أن تقبل الدالة loadState نفس الكائن/القيمة التسلسلية بتنسيق JSON، وتطبقه على الحقل.

saveState() {
  return {
    'country': this.getValue(),  // Value state
    'zoom': this.getZoomLevel(), // UI state
  };
}

loadState(state) {
  this.setValue(state['country']);
  this.setZoomLevel(state['zoom']);
}

التسلسل الكامل والبيانات الاحتياطية

تتلقّى saveState أيضًا المعلَمة الاختيارية doFullSerialization. يُستخدم هذا من خلال الحقول التي تشير عادةً إلى حالة تسلسلية باستخدام serializer مختلف (مثل نماذج البيانات الاحتياطية). تشير المَعلمة إلى أنّ الحالة المُشار إليها لن تكون متاحة عند إلغاء تسلسل الكتلة، لذا يجب أن ينفّذ الحقل جميع عمليات التسلسل بنفسه. على سبيل المثال، يكون هذا صحيحًا عندما تكون كتلة فردية متسلسلة، أو عندما يتم نسخ كتلة.

هناك حالتا استخدام شائعتان لذلك هما:

  • عند تحميل كتلة فردية في مساحة عمل لا يتوفّر فيها نموذج بيانات الاحتياطية، يحتوي الحقل على معلومات كافية في حالته الخاصة لإنشاء نموذج بيانات جديد.
  • عند نسخ كتلة، يقوم الحقل دائمًا بإنشاء نموذج بيانات احتياطي جديد بدلاً من الإشارة إلى نموذج موجود.

أحد الحقول التي تستخدم هذا هو حقل المتغير المضمّن. تعرض هذه الدالة عادةً معرِّف المتغيّر الذي يشير إليه بشكل متسلسل، ولكن إذا كانت القيمة doFullSerialization صحيحة، تعرض كل حالاتها بشكل متسلسل.

saveState(doFullSerialization) {
  const state = {'id': this.variable_.getId()};
  if (doFullSerialization) {
    state['name'] = this.variable_.name;
    state['type'] = this.variable_.type;
  }
  return state;
}

loadState(state) {
  const variable = Blockly.Variables.getOrCreateVariablePackage(
      this.getSourceBlock().workspace,
      state['id'],
      state['name'],   // May not exist.
      state['type']);  // May not exist.
  this.setValue(variable.getId());
}

يفعل حقل المتغير ذلك للتأكد من أنه إذا تم تحميله في مساحة عمل حيث لا يوجد المتغير، فيمكنه إنشاء متغيّر جديد للرجوع إليه.

toXml وfromXml

toXml وfromXml هما عنصر جذب للتسلسل الذي يعمل مع نظام تسلسل XML القديم. لا تستخدِم عناصر الجذب هذه إلا إذا لزم الأمر (على سبيل المثال، إذا كنت تعمل على قاعدة رموز قديمة لم يتم نقلها بعد)، أو استخدِم saveState وloadState.

يجب أن تعرض الدالة toXml عقدة XML تمثل حالة الحقل. ويجب أن تقبل دالة fromXml عقدة XML نفسها وأن تطبّقها على الحقل.

toXml(fieldElement) {
  fieldElement.textContent = this.getValue();
  fieldElement.setAttribute('zoom', this.getZoomLevel());
  return fieldElement;
}

fromXml(fieldElement) {
  this.setValue(fieldElement.textContent);
  this.setZoomLevel(fieldElement.getAttribute('zoom'));
}

الخصائص القابلة للتعديل والقابلة للتسلسل

تحدِّد السمة EDITABLE ما إذا كان يجب أن يحتوي الحقل على واجهة مستخدم للإشارة إلى إمكانية التفاعل معه. القيمة التلقائية هي true.

تحدّد السمة SERIALIZABLE ما إذا كان يجب إنشاء تسلسل للحقل. يكون القيمة الافتراضية هي false. إذا كانت السمة true، قد تحتاج إلى توفير وظيفتَي التسلسل وإلغاء التسلسل (يمكنك الاطّلاع على التسلسل).

تخصيص المؤشر

تحدّد السمة CURSOR المؤشر الذي يراه المستخدمون عند تمرير مؤشر الماوس فوق حقلك. يجب أن تكون القيمة سلسلة صالحة لمؤشر CSS. يتم ضبط هذا الإعداد تلقائيًا على المؤشر الذي يتم تحديده من قِبل .blocklyDraggable، وهو مؤشر الإمساك.