कस्टम फ़ील्ड बनाना

नया फ़ील्ड टाइप बनाने से पहले, यह देख लें कि फ़ील्ड को पसंद के मुताबिक बनाने के लिए, अन्य तरीकों में से कोई तरीका आपकी ज़रूरतों के मुताबिक है या नहीं. अगर आपके ऐप्लिकेशन को किसी नए वैल्यू टाइप को सेव करने की ज़रूरत है या आपको किसी मौजूदा वैल्यू टाइप के लिए नया यूज़र इंटरफ़ेस (यूआई) बनाना है, तो आपको शायद एक नया फ़ील्ड टाइप बनाना होगा.

नया फ़ील्ड बनाने के लिए, यह तरीका अपनाएं:

  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. ज़रूरी नहीं: पसंद के मुताबिक और बदलाव करें. उदाहरण के लिए, लेबल फ़ील्ड की मदद से, सीएसएस क्लास को पास किया जा सकता है. इसके बाद, इसे टेक्स्ट पर लागू किया जाता है.

JSON और रजिस्ट्रेशन

JSON ब्लॉक की परिभाषाओं में, फ़ील्ड को स्ट्रिंग (जैसे, field_number, field_textinput) के ज़रिए बताया जाता है. Blockly, इन स्ट्रिंग से फ़ील्ड ऑब्जेक्ट तक एक मैप बनाए रखता है. साथ ही, कंस्ट्रक्शन के दौरान सही ऑब्जेक्ट पर fromJson को कॉल करता है.

इस मैप में फ़ील्ड टाइप जोड़ने के लिए, Blockly.fieldRegistry.register को कॉल करें. साथ ही, फ़ील्ड क्लास को दूसरे आर्ग्युमेंट के तौर पर पास करें:

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

आपको अपने fromJson फ़ंक्शन को भी तय करना होगा. आपके कोड को लागू करने के दौरान, सबसे पहले स्थानीय भाषा के टोकन के सभी रेफ़रंस को हटाना चाहिए. इसके लिए, replaceMessageReferences का इस्तेमाल करें. इसके बाद, कंस्ट्रक्टर को वैल्यू पास करें.

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

शुरू हो रहा है

जब आपका फ़ील्ड बनाया जाता है, तो इसमें सिर्फ़ एक वैल्यू होती है. इनिशियलाइज़ेशन में, DOM बनाया जाता है. साथ ही, मॉडल बनाया जाता है (अगर फ़ील्ड में मॉडल मौजूद है). इसके अलावा, इवेंट बाइंड किए जाते हैं.

ऑन-ब्लॉक डिसप्ले

शुरुआत में, आपको फ़ील्ड के ऑन-ब्लॉक डिसप्ले के लिए ज़रूरी चीज़ें बनानी होंगी.

डिफ़ॉल्ट सेटिंग, बैकग्राउंड, और टेक्स्ट

डिफ़ॉल्ट initView फ़ंक्शन, हल्के रंग का rect एलिमेंट और text एलिमेंट बनाता है. अगर आपको अपने फ़ील्ड में ये दोनों सुविधाएं और कुछ अतिरिक्त सुविधाएं चाहिए, तो बाकी DOM एलिमेंट जोड़ने से पहले, सुपरक्लास initView फ़ंक्शन को कॉल करें. अगर आपको अपने फ़ील्ड में इनमें से कोई एक एलिमेंट शामिल करना है, तो createBorderRect_ या createTextElement_ फ़ंक्शन का इस्तेमाल करें.

डीओएम कंस्ट्रक्शन को पसंद के मुताबिक बनाना

अगर आपका फ़ील्ड कोई सामान्य टेक्स्ट फ़ील्ड है (जैसे, Text Input), तो आपके लिए DOM कंस्ट्रक्शन को मैनेज किया जाएगा. इसके अलावा, आपको initView फ़ंक्शन को ओवरराइड करना होगा, ताकि उन DOM एलिमेंट को बनाया जा सके जिनकी ज़रूरत आपको फ़ील्ड को आने वाले समय में रेंडर करने के दौरान पड़ेगी.

उदाहरण के लिए, किसी ड्रॉपडाउन फ़ील्ड में इमेज और टेक्स्ट, दोनों हो सकते हैं. initView में, यह एक इमेज एलिमेंट और एक टेक्स्ट एलिमेंट बनाता है. इसके बाद, render_ के दौरान, यह चुने गए विकल्प के टाइप के आधार पर, चालू एलिमेंट को दिखाता है और दूसरे को छिपाता है.

DOM एलिमेंट बनाने के लिए, Blockly.utils.dom.createSvgElement तरीके का इस्तेमाल किया जा सकता है. इसके अलावा, DOM बनाने के पारंपरिक तरीकों का भी इस्तेमाल किया जा सकता है.

किसी फ़ील्ड को ब्लॉक के तौर पर दिखाने के लिए, ये ज़रूरी शर्तें पूरी होनी चाहिए:

  • सभी DOM एलिमेंट, फ़ील्ड के fieldGroup_ के चाइल्ड होने चाहिए. फ़ील्ड ग्रुप अपने-आप बन जाता है.
  • सभी DOM एलिमेंट, फ़ील्ड के बताए गए डाइमेंशन के अंदर होने चाहिए.

ब्लॉक किए गए डिसप्ले को पसंद के मुताबिक बनाने और अपडेट करने के बारे में ज़्यादा जानने के लिए, रेंडरिंग सेक्शन देखें.

टेक्स्ट सिंबल जोड़ना

अगर आपको किसी फ़ील्ड के टेक्स्ट में सिंबल जोड़ने हैं (जैसे कि Angle फ़ील्ड का डिग्री सिंबल), तो सिंबल एलिमेंट को सीधे तौर पर फ़ील्ड के textElement_ में जोड़ा जा सकता है. आम तौर पर, यह <tspan> में शामिल होता है.

इनपुट इवेंट

डिफ़ॉल्ट रूप से फ़ील्ड, टूलटिप इवेंट और mousedown इवेंट रजिस्टर करते हैं. इनका इस्तेमाल एडिटर दिखाने के लिए किया जाता है. अगर आपको अन्य तरह के इवेंट (जैसे, अगर आपको किसी फ़ील्ड पर ड्रैग करने की सुविधा को मैनेज करना है) के बारे में जानना है, तो आपको फ़ील्ड के 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 फ़ंक्शन में अनरजिस्टर करना होगा.

अगर आपने अपने फ़ील्ड के व्यू को सही तरीके से शुरू किया है (सभी डीओएम एलिमेंट को fieldGroup_ में जोड़कर), तो फ़ील्ड का डीओएम अपने-आप बंद हो जाएगा.

वैल्यू हैंडलिंग

→ किसी फ़ील्ड की वैल्यू बनाम उसके टेक्स्ट के बारे में जानने के लिए, किसी फ़ील्ड की बनावट देखें.

पुष्टि करने का क्रम

फ़्लोचार्ट में, यह बताया गया है कि पुष्टि करने वाले टूल किस क्रम में काम करते हैं

क्लास की पुष्टि करने वाले प्रोग्राम को लागू करना

फ़ील्ड में सिर्फ़ कुछ वैल्यू स्वीकार की जानी चाहिए. उदाहरण के लिए, संख्या वाले फ़ील्ड में सिर्फ़ संख्याएं, रंग वाले फ़ील्ड में सिर्फ़ रंग वगैरह स्वीकार किए जाने चाहिए. यह पक्का करने के लिए, क्लास और लोकल वैलडेटर का इस्तेमाल किया जाता है. क्लास वैलिडेटर, लोकल वैलिडेटर के नियमों का पालन करता है. हालांकि, इसे कंस्ट्रक्टर में भी चलाया जाता है. इसलिए, इसे सोर्स ब्लॉक का रेफ़रंस नहीं देना चाहिए.

अपने फ़ील्ड के क्लास वैलिडेटर को लागू करने के लिए, 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 पर सेट करना चाहिए. इसके अलावा, render_ को override करना चाहिए, ताकि ऑन-ब्लॉक डिसप्ले, value_ के बजाय displayValue_ के आधार पर अपडेट हो.

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_ फ़ंक्शन को तय करने पर, Blockly अपने-आप क्लिक के लिए सुनेगा और सही समय पर showEditor_ को कॉल करेगा. अपने एडिटर में कोई भी एचटीएमएल दिखाया जा सकता है. इसके लिए, उसे दो खास डिव में से किसी एक में रैप करें. इन्हें DropDownDiv और WidgetDiv कहा जाता है. ये Blockly के बाकी यूज़र इंटरफ़ेस (यूआई) के ऊपर तैरते हैं.

DropDownDiv का इस्तेमाल, बॉक्स में मौजूद उन एडिटर को उपलब्ध कराने के लिए किया जाता है जो किसी फ़ील्ड से कनेक्ट होते हैं. यह फ़ील्ड के पास अपने-आप सेट हो जाता है. हालांकि, यह दिखता रहता है. ऐंगल पिकर और कलर पिकर, DropDownDiv के अच्छे उदाहरण हैं.

ऐंगल पिकर की इमेज

WidgetDiv का इस्तेमाल ऐसे एडिटर उपलब्ध कराने के लिए किया जाता है जो बॉक्स के अंदर नहीं होते. नंबर फ़ील्ड, WidgetDiv का इस्तेमाल करते हैं, ताकि फ़ील्ड को एचटीएमएल टेक्स्ट इनपुट बॉक्स से कवर किया जा सके. 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, दोनों ही विजेट के एचटीएमएल एलिमेंट को हटाने का काम करते हैं. हालांकि, आपको उन एलिमेंट पर लागू किए गए किसी भी इवेंट लिसनर को मैन्युअल तरीके से हटाना होगा.

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

dispose फ़ंक्शन को DropDownDiv पर null कॉन्टेक्स्ट में कॉल किया जाता है. WidgetDiv पर, इसे WidgetDiv के संदर्भ में कहा जाता है. दोनों ही मामलों में, डिस्पोज़ फ़ंक्शन पास करते समय bind फ़ंक्शन का इस्तेमाल करना सबसे अच्छा होता है. जैसा कि ऊपर दिए गए DropDownDiv और WidgetDiv उदाहरणों में दिखाया गया है.

→ एडिटर को हटाने के अलावा अन्य जानकारी के लिए, हटाना लेख पढ़ें.

ब्लॉक किए गए कॉन्टेंट को डिसप्ले करने की सुविधा को अपडेट किया जा रहा है

render_ फ़ंक्शन का इस्तेमाल, फ़ील्ड के ऑन-ब्लॉक डिसप्ले को अपडेट करने के लिए किया जाता है, ताकि वह इसकी इंटरनल वैल्यू से मेल खा सके.

सामान्य उदाहरणों में ये शामिल हैं:

  • टेक्स्ट बदलना (ड्रॉपडाउन)
  • रंग बदलना (कलर)

डिफ़ॉल्ट

डिफ़ॉल्ट render_ फ़ंक्शन, डिसप्ले टेक्स्ट को getDisplayText_ फ़ंक्शन के नतीजे पर सेट करता है. getDisplayText_ फ़ंक्शन, फ़ील्ड की value_ प्रॉपर्टी को स्ट्रिंग के तौर पर दिखाता है. हालांकि, ऐसा तब होता है, जब टेक्स्ट की ज़्यादा से ज़्यादा लंबाई को ध्यान में रखते हुए, उसे छोटा कर दिया गया हो.

अगर डिफ़ॉल्ट रूप से चालू डिसप्ले का इस्तेमाल किया जा रहा है और डिफ़ॉल्ट टेक्स्ट बिहेवियर आपके फ़ील्ड के लिए काम करता है, तो आपको render_ को ओवरराइड करने की ज़रूरत नहीं है.

अगर डिफ़ॉल्ट टेक्स्ट का व्यवहार आपके फ़ील्ड के लिए काम करता है, लेकिन आपके फ़ील्ड के ऑन-ब्लॉक डिसप्ले में कुछ और स्टैटिक एलिमेंट हैं, तो डिफ़ॉल्ट render_ फ़ंक्शन को कॉल किया जा सकता है. हालांकि, आपको फ़ील्ड का साइज़ अपडेट करने के लिए, इसे अब भी बदलना होगा.

अगर डिफ़ॉल्ट टेक्स्ट बिहेवियर आपके फ़ील्ड के लिए काम नहीं करता है या आपके फ़ील्ड के ऑन-ब्लॉक डिसप्ले में डाइनैमिक एलिमेंट मौजूद हैं, तो आपको render_ फ़ंक्शन को पसंद के मुताबिक बनाना होगा.

फ़्लोचार्ट में बताया गया है कि render_ को ओवरराइड करने का फ़ैसला कैसे लिया जाता है

रेंडरिंग को पसंद के मुताबिक बनाना

अगर डिफ़ॉल्ट रेंडरिंग बिहेवियर आपके फ़ील्ड के लिए काम नहीं करता है, तो आपको कस्टम रेंडरिंग बिहेवियर तय करना होगा. इसमें, पसंद के मुताबिक डिसप्ले टेक्स्ट सेट करने से लेकर इमेज एलिमेंट बदलने और बैकग्राउंड के रंग अपडेट करने तक कुछ भी शामिल हो सकता है.

डीओएम एट्रिब्यूट में किए गए सभी बदलाव मान्य हैं. हालांकि, आपको इन दो बातों का ध्यान रखना होगा:

  1. DOM creation को initialization के दौरान हैंडल किया जाना चाहिए, क्योंकि यह ज़्यादा असरदार होता है.
  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 पर सेट करना होगा.

Blockly, फ़ील्ड के लिए सीरियलाइज़ेशन हुक के दो सेट उपलब्ध कराता है. हुक का एक पेयर, JSON सीरियलाइज़ेशन के नए सिस्टम के साथ काम करता है. वहीं, दूसरा पेयर, XML सीरियलाइज़ेशन के पुराने सिस्टम के साथ काम करता है.

saveState और loadState

saveState और loadState, सीरियलाइज़ेशन हुक हैं. ये नए JSON सीरियलाइज़ेशन सिस्टम के साथ काम करते हैं.

कुछ मामलों में, आपको ये वैल्यू देने की ज़रूरत नहीं होती, क्योंकि डिफ़ॉल्ट रूप से लागू की गई वैल्यू काम करेंगी. अगर (1) आपका फ़ील्ड, base Blockly.Field क्लास का डायरेक्ट सबक्लास है, (2) आपकी वैल्यू JSON serializable type है, और (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 भी मिलता है. इसका इस्तेमाल उन फ़ील्ड के लिए किया जाता है जो आम तौर पर, किसी दूसरे सीरियलाइज़र (जैसे कि बैकिंग डेटा मॉडल) से सीरियल किए गए स्टेटस का रेफ़रंस देते हैं. यह पैरामीटर यह सिग्नल देता है कि ब्लॉक को डिसिरियलाइज़ करने पर, रेफ़र की गई स्थिति उपलब्ध नहीं होगी. इसलिए, फ़ील्ड को पूरा सीरियललाइज़ेशन खुद करना चाहिए. उदाहरण के लिए, ऐसा तब होता है, जब किसी ब्लॉक को क्रम से लगाया जाता है या किसी ब्लॉक को कॉपी करके चिपकाया जाता है.

इसके दो सामान्य इस्तेमाल के उदाहरण यहां दिए गए हैं:

  • जब किसी ब्लॉक को ऐसे वर्कस्पेस में लोड किया जाता है जहां डेटा मॉडल मौजूद नहीं है, तो फ़ील्ड में एक नया डेटा मॉडल बनाने के लिए ज़रूरी जानकारी होती है.
  • किसी ब्लॉक को कॉपी करके चिपकाने पर, फ़ील्ड हमेशा मौजूदा डेटा मॉडल का रेफ़रंस देने के बजाय, एक नया डेटा मॉडल बनाता है.

इस फ़ील्ड का इस्तेमाल करने वाला एक फ़ील्ड, पहले से मौजूद वैरिएबल फ़ील्ड है. आम तौर पर, यह उस वैरिएबल के आईडी को क्रम से लगाता है जिसका वह रेफ़रंस दे रहा है. हालांकि, अगर 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 फ़ंक्शन को एक एक्सएमएल नोड दिखाना चाहिए. यह नोड, फ़ील्ड की स्थिति को दिखाता है. साथ ही, आपके fromXml फ़ंक्शन को उसी एक्सएमएल नोड को स्वीकार करना चाहिए और उसे फ़ील्ड पर लागू करना चाहिए.

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 है, तो आपको सीरियलाइज़ेशन और डीसीरियलाइज़ेशन फ़ंक्शन देने पड़ सकते हैं. इसके बारे में जानने के लिए, सीरियलाइज़ेशन सेक्शन देखें.

सीएसएस का इस्तेमाल करके पसंद के मुताबिक बनाना

सीएसएस का इस्तेमाल करके, फ़ील्ड को अपनी पसंद के मुताबिक बनाया जा सकता है. initView तरीके में, अपने फ़ील्ड के fieldGroup_ में एक कस्टम क्लास जोड़ें. इसके बाद, इस क्लास को अपनी सीएसएस में रेफ़रंस करें.

उदाहरण के लिए, किसी दूसरे कर्सर का इस्तेमाल करने के लिए:

initView() {
  ...

  // Add a custom CSS class.
  if (this.fieldGroup_) {
    Blockly.utils.dom.addClass(this.fieldGroup_, 'myCustomField');
  }
}
.myCustomField {
  cursor: cell;
}

कर्सर को पसंद के मुताबिक बनाना

डिफ़ॉल्ट रूप से, FieldInput बढ़ाने वाली क्लास, उपयोगकर्ता के फ़ील्ड पर कर्सर घुमाने पर text कर्सर का इस्तेमाल करती हैं. साथ ही, ड्रैग किए जा रहे फ़ील्ड, grabbing कर्सर का इस्तेमाल करते हैं. इसके अलावा, अन्य सभी फ़ील्ड, default कर्सर का इस्तेमाल करते हैं. अगर आपको किसी दूसरे कर्सर का इस्तेमाल करना है, तो सीएसएस का इस्तेमाल करके उसे सेट करें.