ایجاد یک نوع فیلد جدید

قبل از ایجاد یک نوع فیلد جدید، در نظر بگیرید که آیا یکی از روش‌های دیگر برای سفارشی‌سازی فیلدها با نیازهای شما مطابقت دارد یا خیر. اگر برنامه شما نیاز به ذخیره یک نوع مقدار جدید دارد، یا می خواهید یک رابط کاربری جدید برای یک نوع مقدار موجود ایجاد کنید، احتمالاً باید یک نوع فیلد جدید ایجاد کنید.

برای ایجاد یک فیلد جدید، موارد زیر را انجام دهید:

  1. یک سازنده را پیاده سازی کنید .
  2. یک کلید JSON ثبت کنید و fromJson پیاده سازی کنید .
  3. تنظیم اولیه رابط کاربری روی بلوک و شنوندگان رویداد را انجام دهید .
  4. رسیدگی به دفع شنوندگان رویداد (دفع UI برای شما انجام می شود).
  5. مدیریت ارزش را پیاده سازی کنید .
  6. برای دسترسی، یک نمایش متنی از مقدار فیلد خود اضافه کنید .
  7. اضافه کردن قابلیت های اضافی مانند:
  8. جنبه های اضافی رشته خود را پیکربندی کنید، مانند:

این بخش فرض می کند که شما مطالب موجود در آناتومی یک میدان را خوانده اید و با آن آشنا هستید.

برای مثالی از یک فیلد سفارشی ، نسخه نمایشی Custom Fields را ببینید.

پیاده سازی سازنده

سازنده فیلد مسئول تنظیم مقدار اولیه فیلد و تنظیم اختیاری یک اعتبارسنجی محلی است. سازنده فیلد سفارشی در طول مقداردهی اولیه بلوک منبع فراخوانی می شود، صرف نظر از اینکه بلوک منبع در JSON یا جاوا اسکریپت تعریف شده باشد. بنابراین، فیلد سفارشی در طول ساخت به بلوک منبع دسترسی ندارد.

نمونه کد زیر یک فیلد سفارشی به نام GenericField ایجاد می کند:

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

    this.SERIALIZABLE = true;
  }
}

امضای روش

سازندگان فیلد معمولاً یک مقدار و یک اعتبارسنجی محلی را می گیرند. مقدار اختیاری است، و اگر مقداری را ارسال نکنید (یا مقداری را ارسال کنید که اعتبار کلاس را با مشکل مواجه کند)، از مقدار پیش‌فرض سوپرکلاس استفاده می‌شود. برای کلاس Field پیش فرض، این مقدار null است. اگر آن مقدار پیش‌فرض را نمی‌خواهید، حتماً یک مقدار مناسب را ارسال کنید. پارامتر اعتبارسنجی فقط برای فیلدهای قابل ویرایش وجود دارد و معمولاً به عنوان اختیاری علامت‌گذاری می‌شود. در اسناد اعتبار سنجی بیشتر بدانید.

ساختار

منطق داخل سازنده شما باید از این جریان پیروی کند:

  1. ابر سازنده ارثی را فراخوانی کنید (همه فیلدهای سفارشی باید از Blockly.Field یا یکی از زیرکلاسهای آن ارث بری شوند) تا مقدار را به درستی مقداردهی اولیه کنید و اعتبارسنجی محلی را برای فیلد خود تنظیم کنید.
  2. اگر فیلد شما قابل سریال سازی است، ویژگی مربوطه را در سازنده تنظیم کنید. فیلدهای قابل ویرایش باید سریال‌سازی شوند و فیلدها به‌طور پیش‌فرض قابل ویرایش هستند، بنابراین احتمالاً باید این ویژگی را روی true تنظیم کنید، مگر اینکه بدانید نباید سریال‌پذیر باشد.
  3. اختیاری: سفارشی‌سازی اضافی را اعمال کنید (برای مثال، فیلدهای Label اجازه می‌دهند یک کلاس css ارسال شود، که سپس روی متن اعمال می‌شود).

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، تابع superclass initView را فراخوانی کنید. اگر می خواهید فیلد شما یکی از این عناصر را داشته باشد، اما نه هر دو، می توانید از توابع createBorderRect_ یا createTextElement_ استفاده کنید.

سفارشی سازی ساخت DOM

اگر فیلد شما یک فیلد متنی عمومی است (مثلاً ورودی متن )، ساخت DOM برای شما انجام می شود. در غیر این صورت باید تابع initView را نادیده بگیرید تا عناصر DOM را ایجاد کنید که در رندر آینده فیلد خود به آن نیاز خواهید داشت.

برای مثال، یک فیلد کشویی ممکن است هم شامل تصاویر و هم متن باشد. در initView یک عنصر تصویر و یک عنصر متن واحد ایجاد می کند. سپس در طول render_ عنصر فعال را نشان می دهد و دیگری را بر اساس نوع گزینه انتخاب شده پنهان می کند.

ایجاد عناصر DOM می تواند با استفاده از روش Blockly.utils.dom.createSvgElement یا با استفاده از روش های سنتی ایجاد DOM انجام شود.

الزامات نمایش روی بلوک یک فیلد عبارتند از:

  • همه عناصر DOM باید فرزندان فیلد fieldGroup_ باشند. گروه فیلد به صورت خودکار ایجاد می شود.
  • همه عناصر DOM باید در ابعاد گزارش شده فیلد باقی بمانند.

برای جزئیات بیشتر در مورد سفارشی‌سازی و به‌روزرسانی صفحه نمایش روی بلوک، به بخش Rendering مراجعه کنید.

اضافه کردن نمادهای متنی

اگر می‌خواهید نمادهایی را به متن یک فیلد اضافه کنید (مانند علامت درجه فیلد زاویه )، می‌توانید عنصر نماد (معمولاً در یک <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 تنظیم کنید، و render_ را لغو کنید تا نمایشگر روی بلوک بر اساس 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_ پرچمی است که در تابع 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_ در زمان مناسب فرا می خواند. شما می توانید هر HTML را در ویرایشگر خود با قرار دادن آن در یکی از دو div ویژه به نام های DropDownDiv و WidgetDiv نمایش دهید که در بالای بقیه رابط کاربری Blockly شناور هستند.

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 نامیده می شود. در هر صورت، همانطور که در مثال‌های DropDownDiv و WidgetDiv در بالا نشان داده شده است، هنگام ارسال یک تابع dispose، بهتر است از تابع bind استفاده کنید.

← برای اطلاعات در مورد دفع غیر اختصاصی به دفع سردبیران، دفع را ببینید.

به روز رسانی صفحه نمایش روی بلوک

تابع render_ برای به روز رسانی صفحه نمایش روی بلوک فیلد برای مطابقت با مقدار داخلی آن استفاده می شود.

نمونه های رایج عبارتند از:

  • تغییر متن (کشویی)
  • تغییر رنگ (رنگ)

پیش فرض ها

تابع render_ پیش‌فرض، متن نمایشگر را روی نتیجه تابع getDisplayText_ تنظیم می‌کند. تابع getDisplayText_ خاصیت value_ فیلد را به رشته ای باز می گرداند، پس از اینکه برای رعایت حداکثر طول متن کوتاه شد.

اگر از نمایشگر روی بلوک پیش‌فرض استفاده می‌کنید و رفتار متن پیش‌فرض برای فیلد شما کار می‌کند، نیازی به لغو render_ نیست.

اگر رفتار متن پیش‌فرض برای فیلد شما کار می‌کند، اما نمایشگر روی بلوک فیلد شما دارای عناصر ثابت اضافی است، می‌توانید تابع 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 را لغو کنید. شما می خواهید از طریق ویژگی style بلوک به رنگ دسترسی داشته باشید.

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) فیلد شما یک زیر کلاس مستقیم از کلاس پایه 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 را دریافت می کند. این مورد توسط فیلدهایی استفاده می‌شود که معمولاً به حالت سریال‌سازی شده توسط سریال‌ساز دیگری (مانند مدل‌های داده پشتیبان) اشاره می‌کنند. این پارامتر نشان می‌دهد که حالت ارجاع‌شده زمانی که بلوک از حالت سریال خارج می‌شود، در دسترس نخواهد بود، بنابراین فیلد باید تمام سریال‌سازی را خودش انجام دهد. به عنوان مثال، زمانی که یک بلوک مجزا سریالی می شود، یا زمانی که یک بلوک کپی پیست شده است، این درست است.

دو مورد استفاده رایج برای این عبارتند از:

  • هنگامی که یک بلوک منفرد در فضای کاری بارگذاری می شود که در آن مدل داده پشتیبان وجود ندارد، فیلد در حالت خودش اطلاعات کافی برای ایجاد یک مدل داده جدید دارد.
  • هنگامی که یک بلوک کپی پیست می شود، این فیلد به جای ارجاع به مدل موجود، همیشه یک مدل داده پشتیبان جدید ایجاد می کند.

یکی از زمینه هایی که از این استفاده می کند، فیلد متغیر داخلی است. معمولاً شناسه متغیری را که به آن ارجاع می دهد سریال می کند، اما اگر 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 تعیین می کند که آیا فیلد باید دارای UI باشد تا نشان دهد که می توان با آن تعامل داشت یا خیر. پیش فرض آن true است.

ویژگی SERIALIZABLE تعیین می کند که آیا فیلد باید سریال شود یا خیر. پیش فرض آن false است. اگر این ویژگی true باشد، ممکن است لازم باشد توابع سریال‌سازی و سریال‌سازی را ارائه کنید (به سریال‌سازی مراجعه کنید).

سفارشی کردن مکان نما

ویژگی CURSOR مکان نما را مشخص می کند که کاربران هنگام حرکت بر روی فیلد شما می بینند. این باید یک رشته مکان نما CSS معتبر باشد. این به طور پیش‌فرض به مکان‌نمای تعریف شده توسط .blocklyDraggable ، که نشانگر گرفتن است، تنظیم می‌شود.

،

قبل از ایجاد یک نوع فیلد جدید، در نظر بگیرید که آیا یکی از روش‌های دیگر برای سفارشی‌سازی فیلدها با نیازهای شما مطابقت دارد یا خیر. اگر برنامه شما نیاز به ذخیره یک نوع مقدار جدید دارد، یا می خواهید یک رابط کاربری جدید برای یک نوع مقدار موجود ایجاد کنید، احتمالاً باید یک نوع فیلد جدید ایجاد کنید.

برای ایجاد یک فیلد جدید، موارد زیر را انجام دهید:

  1. یک سازنده را پیاده سازی کنید .
  2. یک کلید JSON ثبت کنید و fromJson پیاده سازی کنید .
  3. تنظیم اولیه رابط کاربری روی بلوک و شنوندگان رویداد را انجام دهید .
  4. رسیدگی به دفع شنوندگان رویداد (دفع UI برای شما انجام می شود).
  5. مدیریت ارزش را پیاده سازی کنید .
  6. برای دسترسی، یک نمایش متنی از مقدار فیلد خود اضافه کنید .
  7. اضافه کردن قابلیت های اضافی مانند:
  8. جنبه های اضافی رشته خود را پیکربندی کنید، مانند:

این بخش فرض می کند که شما مطالب موجود در آناتومی یک میدان را خوانده اید و با آن آشنا هستید.

برای مثالی از یک فیلد سفارشی ، نسخه نمایشی Custom Fields را ببینید.

پیاده سازی سازنده

سازنده فیلد مسئول تنظیم مقدار اولیه فیلد و تنظیم اختیاری یک اعتبارسنجی محلی است. سازنده فیلد سفارشی در طول مقداردهی اولیه بلوک منبع فراخوانی می شود، صرف نظر از اینکه بلوک منبع در JSON یا جاوا اسکریپت تعریف شده باشد. بنابراین، فیلد سفارشی در طول ساخت به بلوک منبع دسترسی ندارد.

نمونه کد زیر یک فیلد سفارشی به نام GenericField ایجاد می کند:

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

    this.SERIALIZABLE = true;
  }
}

امضای روش

سازندگان فیلد معمولاً یک مقدار و یک اعتبارسنجی محلی را می گیرند. مقدار اختیاری است، و اگر مقداری را ارسال نکنید (یا مقداری را ارسال کنید که اعتبار کلاس را با مشکل مواجه کند)، از مقدار پیش‌فرض سوپرکلاس استفاده می‌شود. برای کلاس Field پیش فرض، این مقدار null است. اگر آن مقدار پیش‌فرض را نمی‌خواهید، حتماً یک مقدار مناسب را ارسال کنید. پارامتر اعتبارسنجی فقط برای فیلدهای قابل ویرایش وجود دارد و معمولاً به عنوان اختیاری علامت‌گذاری می‌شود. در اسناد اعتبار سنجی بیشتر بدانید.

ساختار

منطق داخل سازنده شما باید از این جریان پیروی کند:

  1. ابر سازنده ارثی را فراخوانی کنید (همه فیلدهای سفارشی باید از Blockly.Field یا یکی از زیرکلاسهای آن ارث بری شوند) تا مقدار را به درستی مقداردهی اولیه کنید و اعتبارسنجی محلی را برای فیلد خود تنظیم کنید.
  2. اگر فیلد شما قابل سریال سازی است، ویژگی مربوطه را در سازنده تنظیم کنید. فیلدهای قابل ویرایش باید سریال‌سازی شوند و فیلدها به‌طور پیش‌فرض قابل ویرایش هستند، بنابراین احتمالاً باید این ویژگی را روی true تنظیم کنید، مگر اینکه بدانید نباید سریال‌پذیر باشد.
  3. اختیاری: سفارشی‌سازی اضافی را اعمال کنید (برای مثال، فیلدهای Label اجازه می‌دهند یک کلاس css ارسال شود، که سپس روی متن اعمال می‌شود).

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، تابع superclass initView را فراخوانی کنید. اگر می خواهید فیلد شما یکی از این عناصر را داشته باشد، اما نه هر دو، می توانید از توابع createBorderRect_ یا createTextElement_ استفاده کنید.

سفارشی سازی ساخت DOM

اگر فیلد شما یک فیلد متنی عمومی است (مثلاً ورودی متن )، ساخت DOM برای شما انجام می شود. در غیر این صورت باید تابع initView را نادیده بگیرید تا عناصر DOM را ایجاد کنید که در رندر آینده فیلد خود به آن نیاز خواهید داشت.

برای مثال، یک فیلد کشویی ممکن است هم شامل تصاویر و هم متن باشد. در initView یک عنصر تصویر و یک عنصر متن واحد ایجاد می کند. سپس در طول render_ عنصر فعال را نشان می دهد و دیگری را بر اساس نوع گزینه انتخاب شده پنهان می کند.

ایجاد عناصر DOM می تواند با استفاده از روش Blockly.utils.dom.createSvgElement یا با استفاده از روش های سنتی ایجاد DOM انجام شود.

الزامات نمایش روی بلوک یک فیلد عبارتند از:

  • همه عناصر DOM باید فرزندان فیلد fieldGroup_ باشند. گروه فیلد به صورت خودکار ایجاد می شود.
  • همه عناصر DOM باید در ابعاد گزارش شده فیلد باقی بمانند.

برای جزئیات بیشتر در مورد سفارشی‌سازی و به‌روزرسانی صفحه نمایش روی بلوک، به بخش Rendering مراجعه کنید.

اضافه کردن نمادهای متنی

اگر می‌خواهید نمادهایی را به متن یک فیلد اضافه کنید (مانند علامت درجه فیلد زاویه )، می‌توانید عنصر نماد (معمولاً در یک <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 تنظیم کنید، و render_ را لغو کنید تا نمایشگر روی بلوک بر اساس 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_ پرچمی است که در تابع 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_ در زمان مناسب فرا می خواند. شما می توانید هر HTML را در ویرایشگر خود با قرار دادن آن در یکی از دو div ویژه به نام های DropDownDiv و WidgetDiv نمایش دهید که در بالای بقیه رابط کاربری Blockly شناور هستند.

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 نامیده می شود. در هر صورت، همانطور که در مثال‌های DropDownDiv و WidgetDiv در بالا نشان داده شده است، هنگام ارسال یک تابع dispose، بهتر است از تابع bind استفاده کنید.

← برای اطلاعات در مورد دفع غیر اختصاصی به دفع سردبیران به دفع مراجعه کنید.

به روز رسانی صفحه نمایش روی بلوک

از عملکرد render_ برای به روزرسانی صفحه نمایش در بلوک استفاده می شود تا با مقدار داخلی آن مطابقت داشته باشد.

نمونه های رایج عبارتند از:

  • تغییر متن (کشویی)
  • تغییر رنگ (رنگ)

پیش فرض ها

عملکرد پیش فرض render_ متن نمایش را به نتیجه عملکرد getDisplayText_ تنظیم می کند. عملکرد getDisplayText_ پس از کوتاه شدن برای احترام به حداکثر طول متن ، ویژگی value_ Field را به یک رشته باز می گرداند.

اگر از صفحه نمایش پیش فرض در بلوک استفاده می کنید و رفتار متنی پیش فرض برای زمینه شما کار می کند ، نیازی به غلبه بر 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;
  }
}

سریال سازی

سریال سازی در مورد صرفه جویی در وضعیت حوزه شما است تا بعداً در فضای کاری بارگیری شود.

وضعیت فضای کاری شما همیشه شامل ارزش این زمینه است ، اما می تواند وضعیت دیگری مانند وضعیت UI حوزه شما را نیز شامل شود. به عنوان مثال ، اگر زمینه شما یک نقشه بزرگنمایی بود که به کاربر امکان انتخاب کشورها را می داد ، می توانید سطح زوم را نیز سریال کنید.

اگر فیلد شما قابل سریال است ، باید ویژگی SERIALIZABLE را روی true تنظیم کنید.

Blockly دو مجموعه قلاب سریال سازی را برای زمینه ها فراهم می کند. یک جفت قلاب با سیستم سریال سازی جدید 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 دریافت می کند. این توسط زمینه هایی استفاده می شود که به طور معمول از سریال های سریال متفاوت استفاده می کنند (مانند مدل های داده پشتیبان). این پارامتر نشان می دهد که حالت ارجاع شده در صورت عدم استفاده از بلوک در دسترس نخواهد بود ، بنابراین این زمینه باید تمام سریال سازی را انجام دهد. به عنوان مثال ، وقتی یک بلوک جداگانه سریال می شود ، یا هنگامی که یک بلوک کپی شده است ، صادق است.

دو مورد استفاده متداول برای این موارد عبارتند از:

  • هنگامی که یک بلوک جداگانه در یک فضای کاری بارگیری می شود که در آن مدل داده های پشتیبان وجود ندارد ، این زمینه اطلاعات کافی در حالت خود برای ایجاد یک مدل داده جدید دارد.
  • هنگامی که یک بلوک کپی شده است ، این زمینه همیشه به جای مراجعه به یک مورد موجود ، یک مدل داده پشتیبان جدید ایجاد می کند.

یک زمینه که از این استفاده می کند ، زمینه متغیر داخلی است. به طور معمول ، شناسه متغیری را که به آن اشاره می کند سریال می کند ، اما اگر 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 مشخص می کند که آیا این زمینه باید از UI برخوردار باشد تا نشان دهد که می توان با آن تعامل داشت. این به طور پیش فرض به true است.

ویژگی SERIALIZABLE تعیین می کند که آیا این زمینه باید سریال شود یا خیر. این به طور پیش فرض false است. اگر این ویژگی true باشد ، ممکن است شما نیاز به ارائه سریال سازی و توابع deserialization داشته باشید (به سریال سازی مراجعه کنید).

سفارشی کردن مکان نما

ویژگی CURSOR مکان نما را که کاربران هنگام شناور در قسمت شما می بینند ، تعیین می کند. این باید یک رشته مکان نما CSS معتبر باشد. این پیش فرض به مکان نما تعریف شده توسط .blocklyDraggable ، که مکان نما Grab است.