Tworzenie nowego typu pola

Zanim utworzysz nowy typ pola, zastanów się, czy któraś z innych metod dostosowywania pól nie odpowiada Twoim potrzebom. Jeśli aplikacja musi przechowywać nowy typ wartości lub jeśli chcesz utworzyć nowy interfejs dla istniejącego typu wartości, prawdopodobnie musisz utworzyć nowy typ pola.

Aby utworzyć nowe pole:

  1. Zaimplementuj konstruktor.
  2. Zarejestruj klucz JSON i zaimplementuj fromJson.
  3. Obsługa inicjowania interfejsu użytkownika bloku i odbiorników zdarzeń
  4. Usuwaj detektory zdarzeń (usuwanie w interfejsie odbywa się za Ciebie).
  5. Wdróż obsługę wartości.
  6. Dodaj tekstowe przedstawienie wartości pola na potrzeby ułatwień dostępu.
  7. Możesz korzystać z dodatkowych funkcji, takich jak:
  8. Skonfiguruj dodatkowe aspekty pola, takie jak:

W tej sekcji zakładamy, że znasz już treść artykułu Anatomia pola.

Przykład pola niestandardowego znajdziesz w prezentacji o polach niestandardowych.

Implementowanie konstruktora

Konstruktor pola odpowiada za ustawienie początkowej wartości pola oraz opcjonalnie skonfigurowanie lokalnego walidatora. Konstruktor pola niestandardowego jest wywoływany podczas inicjowania bloku źródłowego niezależnie od tego, czy blok źródłowy jest zdefiniowany w formacie JSON czy JavaScript. Pole niestandardowe nie ma więc dostępu do bloku źródłowego podczas tworzenia.

Ten przykładowy kod tworzy pole niestandardowe o nazwie GenericField:

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

    this.SERIALIZABLE = true;
  }
}

Podpis metody

Konstruktory pól zwykle przyjmują wartość i lokalny walidator. Wartość jest opcjonalna. Jeśli nie przekażesz wartości (lub wartości, która nie przejdzie weryfikacji klasy), zostanie użyta wartość domyślna klasy nadrzędnej. W przypadku domyślnej klasy Field ta wartość wynosi null. Jeśli nie chcesz używać tej wartości domyślnej, prześlij odpowiednią wartość. Parametr walidatora występuje tylko w polach do edycji i jest zwykle oznaczony jako opcjonalny. Więcej informacji o walidatorach znajdziesz w dokumentacji walidatorów.

Struktura

Logika konstruktora powinna wyglądać tak:

  1. Wywołaj dziedziczony superkonstruktor (wszystkie pola niestandardowe powinny dziedziczyć z klasy Blockly.Field lub jednej z jej podklas), aby prawidłowo zainicjować wartość i ustawić lokalny walidator pola.
  2. Jeśli pole można zserializować, ustaw odpowiednią właściwość w konstruktorze. Pola, które można edytować, muszą być serializowane, a pola domyślnie można edytować, więc prawdopodobnie ustaw tę właściwość na „true” (prawda), chyba że wiesz, że nie powinna być ona szeregowa.
  3. Opcjonalnie: zastosuj dodatkowe dostosowanie (np. pola etykiet umożliwiają przekazywanie klasy CSS, która jest następnie stosowana do tekstu).

JSON i rejestracja

W definicjach bloków JSON pola są opisywane ciągiem znaków (np. field_number, field_textinput). Blockly zachowuje mapowanie tych ciągów znaków na obiekty pól i wywołuje fromJson do odpowiedniego obiektu podczas tworzenia.

Wywołaj Blockly.fieldRegistry.register, aby dodać typ pola do tej mapy, przekazując klasę pola jako drugi argument:

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

Musisz też zdefiniować funkcję fromJson. W implementacji należy najpierw usunąć odniesienia do wszystkich odwołań do tabeli ciągów za pomocą funkcji replaceMessageReferences, a potem przekazać wartości do konstruktora.

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

Inicjuję

W ramach tworzenia pola znajduje się w nim tylko wartość. Inicjacja to miejsce, w którym tworzony jest DOM, model jest tworzony (jeśli pole zawiera model), a zdarzenia są powiązane.

Ekran typu Blokuj ekran

Podczas inicjowania odpowiadasz za utworzenie wszystkiego, co jest potrzebne do wyświetlania pola.

Domyślne ustawienia, tło i tekst

Domyślna funkcja initView tworzy element rect w jasnym kolorze i element text. Jeśli chcesz, aby pole miało oba te elementy oraz dodatkowe korzyści, wywołaj funkcję initView superklasy przed dodaniem pozostałych elementów DOM. Jeśli chcesz, aby pole miało jeden z tych elementów, ale nie oba, możesz użyć funkcji createBorderRect_ lub createTextElement_.

Dostosowywanie konstrukcji DOM

Jeśli pole jest standardowym polem tekstowym (np. Dane wejściowe), konstrukcja DOM zostanie wykonana za Ciebie. W przeciwnym razie musisz zastąpić funkcję initView, aby utworzyć elementy DOM, których będziesz potrzebować podczas przyszłego renderowania pola.

Na przykład pole rozwijane może zawierać zarówno obrazy, jak i tekst. W initView tworzy 1 element graficzny i 1 element tekstowy. Następnie w okresie render_ wyświetla aktywny element i ukrywa drugi na podstawie typu wybranej opcji.

Elementy DOM można tworzyć za pomocą metody Blockly.utils.dom.createSvgElement lub tradycyjnych metod tworzenia DOM.

Wymagania dotyczące wyświetlania pola w bloku to:

  • Wszystkie elementy DOM muszą być elementami podrzędnymi fieldGroup_ pola. Grupa pól zostanie utworzona automatycznie.
  • Wszystkie elementy DOM muszą mieścić się w raportowanych wymiarach pola.

Więcej informacji o dostosowywaniu i aktualizowaniu wyświetlacza na ekranie znajdziesz w sekcji Renderowanie.

Dodawanie symboli tekstowych

Jeśli chcesz dodać symbole do tekstu pola (np. symbol stopni w polu Kąt), możesz dołączyć element symbolu (zwykle zawarty w <tspan>) bezpośrednio do parametru textElement_ tego pola.

Zdarzenia wejściowe

Domyślnie pola rejestrują zdarzenia etykietki i zdarzenia kursora myszy (które służą do wyświetlania edytorów). Jeśli chcesz wykrywać zdarzenia innego typu (np. obsługiwać przeciąganie w polu), zastąp funkcję bindEvents_ tego pola.

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

Aby powiązać ze zdarzeniem, użyj funkcji Blockly.utils.browserEvents.conditionalBind. Ta metoda wiązania zdarzeń odfiltrowuje dodatkowe kliknięcia podczas przeciągania. Jeśli chcesz, aby moduł obsługi był uruchamiany nawet w trakcie przeciągania, możesz użyć funkcji Blockly.browserEvents.bind.

Utylizacja

Jeśli masz zarejestrowane detektory zdarzeń niestandardowych w funkcji bindEvents_ tego pola, musisz je wyrejestrować w ramach funkcji dispose.

Jeśli prawidłowo zainicjujesz widok pola (przez dołączenie wszystkich elementów DOM do fieldGroup_), to DOM dla tego pola zostanie usunięty automatycznie.

Obsługa wartości

→ Informacje o wartości pola i jego tekście znajdziesz w artykule Anatomia pola.

Kolejność weryfikacji

Schemat blokowy opisujący kolejność uruchamiania walidatorów

Wdrażanie walidatora klas

Pola powinny przyjmować tylko określone wartości. Na przykład pola liczbowe powinny akceptować tylko liczby, pola kolorów – tylko kolory itp. Jest to możliwe dzięki klasom i lokalnym walidatorom. Walidator klas działa tak samo jak lokalne walidatory, z tym że jest uruchamiany w konstruktorze i dlatego nie powinien odwoływać się do bloku źródłowego.

Aby wdrożyć walidator klas pola, zastąp funkcję doClassValidation_.

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

Obsługa prawidłowych wartości

Jeśli wartość przekazana do pola z setValue jest prawidłowa, otrzymasz wywołanie zwrotne doValueUpdate_. Domyślnie funkcja doValueUpdate_:

  • Ustawia właściwość value_ na newValue.
  • Ustawia wartość właściwości isDirty_ na true.

Jeśli chcesz po prostu zapisać wartość i nie chcesz stosować żadnej niestandardowej obsługi, nie musisz zastępować atrybutu doValueUpdate_.

W przeciwnym razie możesz:

  • Pamięć niestandardowa newValue.
  • Zmień inne usługi na podstawie: newValue.
  • Zapisz, czy bieżąca wartość jest prawidłowa.

Musisz zastąpić zasadę doValueUpdate_:

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

Obsługa nieprawidłowych wartości

Jeśli wartość przekazana do pola z setValue jest nieprawidłowa, otrzymasz wywołanie zwrotne doValueInvalid_. Domyślnie funkcja doValueInvalid_ nic nie robi. Oznacza to, że domyślnie nieprawidłowe wartości nie będą wyświetlane. Oznacza to również, że pole nie zostanie ponownie wyrenderowane, ponieważ właściwość isDirty_ nie zostanie ustawiona.

Jeśli chcesz wyświetlić nieprawidłowe wartości, zastąp doValueInvalid_. W większości przypadków należy ustawić wartość właściwości displayValue_ na nieprawidłową wartość, ustawić isDirty_ na true i zastąpić renderowanie_ w przypadku wyświetlenia blokowego, aby aktualizowało się na podstawie displayValue_, a nie value_.

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

Wartości wieloczęściowe

Jeśli pole zawiera wartość wieloczęściową (np. listy, wektory, obiekty), możesz chcieć, aby części były traktowane jak pojedyncze wartości.

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

W powyższym przykładzie każda właściwość obiektu newValue jest sprawdzana indywidualnie. Jeśli któraś właściwość jest nieprawidłowa, na końcu funkcji doClassValidation_ wartość jest przechowywana w pamięci podręcznej właściwości cacheValidatedValue_, a następnie zwracana wartość null (nieprawidłowa). Zapisywanie obiektów w pamięci podręcznej z pojedynczymi właściwościami pozwala funkcji doValueInvalid_ obsługiwać je oddzielnie, przeprowadzając sprawdzanie !this.cacheValidatedValue_.property zamiast ponownie weryfikować każdą właściwość z osobna.

Z tego wzorca do weryfikacji wartości wieloczęściowych można też korzystać w lokalnych walidatorach, ale obecnie nie da się go wymusić.

isDirty_

isDirty_ to flaga używana w funkcji setValue oraz w innych częściach pola, aby określić, czy pole należy wyrenderować ponownie. Jeśli wyświetlana wartość pola uległa zmianie, isDirty_ zazwyczaj należy ustawić na true.

Tekst

→ Informacje o tym, gdzie jest używany tekst pola i czym różni się on od jego wartości, znajdziesz w artykule Anatomia pola.

Jeśli treść pola różni się od wartości pola, zastąp funkcję getText, aby wpisać prawidłowy tekst.

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

Tworzenie edytora

Jeśli zdefiniujesz funkcję showEditor_, Blockly będzie automatycznie nasłuchiwać kliknięć i wywołać funkcję showEditor_ w odpowiednim momencie. Możesz wyświetlić dowolny kod HTML w edytorze, zawijając go do jednego z dwóch specjalnych elementów div o nazwie DropDownDiv i WidgetDiv, które unoszą się nad pozostałymi elementami interfejsu Blockly.

DropDownDiv umożliwia edytorom, którzy znajdują się w obiekcie połączonym z polem. Automatycznie ustawia się w pobliżu pola, a jednocześnie mieści się w widocznym obszarze. Dobrymi przykładami właściwości DropDownDiv są selektor kąta i selektor kolorów.

Obraz selektora kąta

WidgetDiv służy do udostępniania edytorów, które nie znajdują się w polu. Pola liczbowe korzystają z WidgetDiv do zasłaniania pola polem do wprowadzania tekstu HTML. Pozycjonowanie za pomocą uchwytów DropDownDiv jest natomiast możliwe w przypadku narzędzia WidgetDiv. Elementy należy ustawić ręcznie. Układ współrzędnych podany jest we współrzędnych piksela względem lewego górnego rogu okna. Dobrym przykładem funkcji WidgetDiv jest edytor do wprowadzania tekstu.

Obraz edytora wprowadzania tekstu

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

Przykładowy kod 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);
}

Czyszczenie

Zarówno uchwyt DropDownDiv, jak i uchwyt WidgetDiv niszczą elementy HTML widżetu, ale musisz ręcznie pozbyć się detektorów zdarzeń zastosowanych do tych elementów.

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

Funkcja dispose jest wywoływana w kontekście null w elemencie DropDownDiv. Na urządzeniu WidgetDiv jest ono wywoływane w kontekście obiektu WidgetDiv. W obu przypadkach najlepiej jest użyć funkcji bind podczas przekazywania funkcji dispose, jak pokazano w powyższych przykładach DropDownDiv i WidgetDiv.

→ Informacje na temat utylizacji, które nie są związane z utylizowaniem redaktorów, znajdziesz w artykule Nikonikowanie.

Aktualizacja wyświetlacza blokowego

Funkcja render_ służy do aktualizowania wyświetlacza w bloku pola, tak aby pasował do jego wewnętrznej wartości.

Typowe przykłady:

  • Zmiana tekstu (menu)
  • Zmiana koloru

Domyślne

Domyślna funkcja render_ ustawia wyświetlany tekst na wynik funkcji getDisplayText_. Funkcja getDisplayText_ zwraca właściwość value_ pola rzutowaną na ciąg znaków po skróceniu z uwzględnieniem maksymalnej długości tekstu.

Jeśli używasz domyślnego wyświetlania blokad, a domyślne zachowanie tekstu w Twoim polu działa, nie musisz zastępować parametru render_.

Jeśli w przypadku Twojego pola działa domyślny tekst, ale w przypadku tego pola dostępne są dodatkowe elementy statyczne, możesz wywołać domyślną funkcję render_, ale i tak musisz ją zastąpić, by zmienić rozmiar pola.

Jeśli domyślne zachowanie tekstu nie działa w przypadku Twojego pola lub wyświetlane w nim elementy wyświetlane w bloku mają dodatkowe elementy dynamiczne, musisz dostosować funkcję render_.

Schemat blokowy opisujący, jak podjąć decyzję o zastąpieniu parametru render_

Dostosowywanie renderowania

Jeśli domyślne zachowanie renderowania nie działa w Twoim polu, musisz zdefiniować niestandardowe zachowanie renderowania. Może to obejmować wszystko: od ustawienia niestandardowego tekstu przez zmianę elementów obrazu po zmianę kolorów tła.

Wszystkie zmiany atrybutów DOM są zgodne z prawem. Należy pamiętać tylko o 2 kwestiach:

  1. Tworzenie DOM powinno być przeprowadzane podczas inicjowania, ponieważ jest to bardziej efektywne.
  2. Zawsze musisz zaktualizować właściwość size_, aby pasowała do rozmiaru wyświetlacza blokowego.
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_();
}

Aktualizuję rozmiar

Aktualizacja właściwości size_ pola jest bardzo ważna, ponieważ informuje kod renderowania blokowego o położeniu pola. Aby dowiedzieć się, co dokładnie powinna mieć wartość size_, najlepiej jest poeksperymentować.

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

Dopasowane kolory bloków

Jeśli chcesz, aby elementy pola były zgodne z kolorami bloku, do którego są dołączone, zastąp metodę applyColour. Dostęp do koloru należy uzyskać za pomocą właściwości stylu bloku.

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

Aktualizuję możliwość edytowania

Za pomocą funkcji updateEditable możesz zmieniać wygląd pola w zależności od tego, czy można je edytować. Funkcja domyślna sprawia, że w tle pojawia się odpowiedź po najechaniu kursorem (obramowanie) – jeśli jej nie można edytować. Rozmiar wyświetlany podczas blokowania nie powinien zmieniać rozmiaru w zależności od możliwości edytowania, ale wszelkie inne zmiany są dozwolone.

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

Serializacja

Serializacja polega na zapisywaniu stanu pola, aby można było później ponownie załadować je do obszaru roboczego.

Stan obszaru roboczego zawsze zawiera wartość pola, ale może też zawierać inny stan, na przykład stan interfejsu pola. Jeśli na przykład pole to mapa z możliwością powiększania i umożliwiająca użytkownikowi wybranie krajów, możesz też serializować poziom powiększenia.

Jeśli Twoje pole można serializować, ustaw właściwość SERIALIZABLE na true.

Blockly udostępnia 2 zestawy punktów zaczepienia serializacji dla pól. Jedna para zaczepów działa z nowym systemem serializacji JSON, a druga ze starym systemem serializacji XML.

saveStateloadState

saveState i loadState to punkty zaczepienia serializacji, które działają z nowym systemem serializacji JSON.

W niektórych przypadkach nie trzeba ich podawać, ponieważ będą działać domyślne implementacje. Jeśli (1) Twoje pole jest bezpośrednią podklasą klasy podstawowej Blockly.Field, (2) wartość jest typem zserializowanym w JSON oraz (3) musisz tylko przeprowadzić serializację wartości, wtedy domyślna implementacja będzie działać prawidłowo.

W przeciwnym razie funkcja saveState powinna zwracać możliwe do zserializowania obiekt/wartość JSON, która reprezentuje stan pola. A funkcja loadState powinna akceptować ten sam obiekt/wartość JSON z możliwością serializowania i zastosować go do pola.

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

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

Pełna serializacja i tworzenie kopii zapasowych danych

saveState otrzymuje też opcjonalny parametr doFullSerialization. Jest ona używana w przypadku pól, które zwykle odwołują się do stanu zserializowanego przez inny serializer (np. zapasowe modele danych). Parametr sygnalizuje, że dany stan nie będzie dostępny, gdy blok zostanie poddany deserializacji, dlatego pole powinno wykonywać całą serializację. Dzieje się tak np. wtedy, gdy pojedynczy blok jest zserializowany lub gdy blok jest kopiowany i wklejany.

Oto 2 typowe przypadki użycia tej funkcji:

  • Po wczytaniu pojedynczego bloku do obszaru roboczego, w którym nie istnieje bazowy model danych, pole ma wystarczającą ilość informacji w swoim stanie, aby utworzyć nowy model danych.
  • Gdy blok jest skopiowany i wklejony, pole zawsze tworzy nowy zapasowy model danych, zamiast odwoływać się do istniejącego.

Jedno z nich to pole wbudowanej zmiennej. Zwykle zserializuje identyfikator zmiennej, do której się odwołuje, ale jeśli doFullSerialization ma wartość prawda, zserializuje cały swój stan.

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

Pole zmiennej ma służyć do zapewnienia, że jeśli zostanie wczytane w obszarze roboczym, w którym nie ma odpowiedniej zmiennej, może utworzyć nową zmienną, do której się ona odwoła.

toXmlfromXml

toXml i fromXml to punkty zaczepienia serializacji, które działają ze starym systemem serializacji XML. Używaj tych punktów zaczepienia tylko wtedy, gdy to konieczne (np.pracujesz nad starą bazą kodu, która nie została jeszcze przeniesiona). W innych przypadkach używaj saveState i loadState.

Funkcja toXml powinna zwracać węzeł XML, który reprezentuje stan pola. Funkcja fromXml powinna akceptować ten sam węzeł XML i stosować go do pola.

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

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

Właściwości możliwe do edycji i serializacji

Właściwość EDITABLE określa, czy pole powinno mieć interfejs wskazujący, z którym można wchodzić w interakcje. Domyślna wartość to true.

Właściwość SERIALIZABLE określa, czy pole powinno być zserializowane. Domyślna wartość to false. Jeśli ta właściwość to true, może być konieczne udostępnienie funkcji serializacji i deserializacji (patrz Serializacja).

Dostosowywanie kursora

Właściwość CURSOR określa kursor, który użytkownicy widzą po najechaniu kursorem na pole. Powinien to być prawidłowy ciąg kursora CSS. Domyślnie jest to kursor zdefiniowany przez atrybut .blocklyDraggable, który jest chwytanym kursorem.