नया फ़ील्ड टाइप बनाना

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

नया फ़ील्ड बनाने के लिए, ये काम करें:

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

बनावट

आपके कंस्ट्रक्टर के अंदर का लॉजिक इस फ़्लो के हिसाब से होना चाहिए:

  1. वैल्यू को सही तरीके से शुरू करने और अपने फ़ील्ड के लिए लोकल वैलिडेटर सेट करने के लिए, इनहेरिट किए गए सुपर कंस्ट्रक्टर (सभी कस्टम फ़ील्ड को Blockly.Field या इसकी किसी सब-क्लास से इनहेरिट किया जाना चाहिए) को कॉल करें.
  2. अगर आपके फ़ील्ड को क्रम से लगाया जा सकता है, तो कंस्ट्रक्टर में उससे जुड़ी प्रॉपर्टी सेट करें. जिन फ़ील्ड में बदलाव किया जा सकता है उन्हें क्रम से लगाया जा सकता है. साथ ही, फ़ील्ड में डिफ़ॉल्ट रूप से बदलाव किया जा सकता है. इसलिए, शायद आपको इस प्रॉपर्टी को 'सही' पर तब तक सेट करना चाहिए, जब तक आपको पता न हो कि इसे क्रम से नहीं लगाया जाना चाहिए.
  3. ज़रूरी नहीं: अतिरिक्त कस्टमाइज़ेशन लागू करें (उदाहरण के लिए, लेबल फ़ील्ड, एक css क्लास को पास करने की अनुमति देता है, फिर उसे टेक्स्ट पर लागू किया जाता है).

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

JSON ब्लॉक की परिभाषाएं में, फ़ील्ड के बारे में स्ट्रिंग से जानकारी दी जाती है (जैसे कि field_number, field_textinput). इस फ़ील्ड में, इन स्ट्रिंग से फ़ील्ड ऑब्जेक्ट में मैप को ब्लॉक रूप से रखा जाता है. साथ ही, कंस्ट्रक्शन के दौरान सही ऑब्जेक्ट को 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);
};

शुरू हो रहा है

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

ब्लॉक पर डिसप्ले

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

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

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

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

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

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

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

किसी फ़ील्ड के ऑन-ब्लॉक डिसप्ले के लिए ये ज़रूरी हैं:

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

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

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

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

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

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

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

सफ़ाई की जा रही है

ड्रॉपडाउन और 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_ फ़ंक्शन को पसंद के मुताबिक बनाना होगा.

फ़्लोचार्ट यह बताता है कि रेंडर को बदलना है या नहीं_

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

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

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 सीरियलाइज़ेशन सिस्टम के साथ काम करता है और दूसरा हुक पुराने एक्सएमएल सीरियलाइज़ेशन सिस्टम के साथ काम करता है.

saveState और loadState

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

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

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

CURSOR प्रॉपर्टी की मदद से यह तय किया जाता है कि उपयोगकर्ता आपके फ़ील्ड पर कर्सर घुमाते समय किस कर्सर को देख सकते हैं. यह एक मान्य सीएसएस कर्सर स्ट्रिंग होनी चाहिए. यह डिफ़ॉल्ट रूप से .blocklyDraggable के तय किए गए कर्सर पर सेट होता है, जो कि ग्रैब कर्सर है.