Wednesday, November 2, 11
CUSTOM COMPONENTS
                            Sven Brunken



             sven@sencha.com               @svenbrunken




Wednesday, November 2, 11
Overview
                                    Widget vs Component
                            Important methods of the Widget class
                                 When to use the Cell class?
                              Important methods of the Cell class
                                         Questions




Wednesday, November 2, 11
Which Class To Start
                            From?




Wednesday, November 2, 11
Widget
       Build on top of a DOM Element
       Listens to browser events
       Needs to be attached and detached for event handling
       Does not solve the different sizing boxes
       Can fire custom events through its HandlerManager




Wednesday, November 2, 11
Component
       Extends the Widget class and so inherits all its features
       Solves the different sizing boxes
       Can be disabled directly
       Can be positioned




Wednesday, November 2, 11
Important Methods




Wednesday, November 2, 11
sinkEvents()
       Defines which events can be listened to
       Events not sunk cannot be listened to



   public void sinkEvents(int eventBitsToAdd) {
     if (isOrWasAttached()) {
       DOM.sinkEvents(getElement(), eventBitsToAdd|DOM.getEventsSunk(getElement()));
     } else {
       eventsToSink |= eventBitsToAdd;
     }
   }




Wednesday, November 2, 11
onAttach()
       Removes the event listener
       Mandatory to enable browser event handling
       Attaches the event listener of all its children widgets

                            protected void onAttach() {
                              attached = true;
                              DOM.setEventListener(getElement(), this);
                              int bitsToAdd = eventsToSink;
                              eventsToSink = -1;
                              if (bitsToAdd > 0) {
                                sinkEvents(bitsToAdd);
                              }
                              doAttachChildren();
                              onLoad();
                              AttachEvent.fire(this, true);
                            }


Wednesday, November 2, 11
onDetach()
       Removes the event listener added from onAttach()
       Browser events are no longer handled for this Widget
       Prevents memory leaks
       Detaches the event listener for all its children widgets

                            protected void onDetach() {
                              try {
                                onUnload();
                                AttachEvent.fire(this, false);
                              } finally {
                                try {
                                  doDetachChildren();
                                } finally {
                                  DOM.setEventListener(getElement(), null);
                                  attached = false;
                                }
                              }
                            }
Wednesday, November 2, 11
fireEvent()
       Fires a custom event through the HandlerManager
       Other classes could listen to these events



                            public void fireEvent(GwtEvent<?> event) {
                              if (handlerManager != null) {
                                handlerManager.fireEvent(event);
                              }
                            }




Wednesday, November 2, 11
onBrowserEvent()
       Only called when a Widget is attached
       Gets called with the browser event that occurred
       Refires the browser event through the HandlerManager




                public void onBrowserEvent(Event event) {
                  DomEvent.fireNativeEvent(event, this, this.getElement());
                }




Wednesday, November 2, 11
setElement()
       Sets the element for this Widget
       Mandatory to be called
       An Element can only be set once and not changed
       Needs to be called before calling getElement()




             protected void setElement(Element elem) {
               assert (element == null) : SETELEMENT_TWICE_ERROR;
               this.element = elem;
             }




Wednesday, November 2, 11
How To Start?




Wednesday, November 2, 11
Gathering Information
       What is the purpose of my custom widget?
       Which browser events are required?
       Can I extend an already existing class?




       Do I understand all my requirements?




Wednesday, November 2, 11
Implementation




Wednesday, November 2, 11
The Class
       Extending Component to overcome different sizing models




                            public class SquareWidget extends Component {

                            }




Wednesday, November 2, 11
Constructor
       Setting the Element
       Defining the events we want to listen to



           public SquareWidget(Data data) {
             this.data = data;
             SquareWidgetTemplate t = GWT.create(SquareWidgetTemplate.class);
             setElement(XDOM.create(t.render(data)));

                sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT | Event.ONCLICK);

                setPixelSize(100, 100);
           }




Wednesday, November 2, 11
onBrowserEvent()
       Contains our event handling logic
       Should call the super method

                        @Override
                        public void onBrowserEvent(Event event) {
                          super.onBrowserEvent(event);

                            if (event.getTypeInt() == Event.ONMOUSEOUT) {
                              onMouseOut(event);
                            } else if (event.getTypeInt() == Event.ONMOUSEOVER) {
                              onMouseOver(event);
                            } else if (event.getTypeInt() == Event.ONCLICK) {
                              onClick(event);
                            }
                        }

Wednesday, November 2, 11
onMouseOver()
       getRelatedEventTarget returns the Element coming from
       Setting the mouse over value




      private void onMouseOver(Event event) {
        EventTarget t = event.getRelatedEventTarget();
        if (t == null || Element.is(t) && !getElement().isOrHasChild(Element.as(t))) {
          String s = SafeHtmlUtils.fromString(data.getMouseOverName()).asString();
          getContentElement().setInnerHTML(s);
        }
      }




Wednesday, November 2, 11
onMouseOut()
       getRelatedEventTarget returns the Element moving to
       Clearing the background color
       Setting the standard value again


             private void onMouseOut(Event event) {
               EventTarget t = event.getRelatedEventTarget();
               if (t == null
                   || (Element.is(t) && !getElement().isOrHasChild(Element.as(t)))) {
                 getElement().getStyle().clearBackgroundColor();

                     String s = SafeHtmlUtils.fromString(data.getName()).asString();
                     getContentElement().setInnerHTML(s);
                 }
             }




Wednesday, November 2, 11
onClick()
       Sets the different background color




                            private void onClick(Event event) {
                              getElement().getStyle().setBackgroundColor("red");
                            }




Wednesday, November 2, 11
Demonstration




Wednesday, November 2, 11
But, Do We Really
                            Require a Widget?




Wednesday, November 2, 11
Introducing Cell
       Cells can handle browser events
       Cells can be used in data components
       Widgets cannot be used there
       Cells render a lot faster




Wednesday, November 2, 11
Context of the Cell
       Contains the relevant row and column index
       Important when used in data widgets
       Contains the key representing the value




Wednesday, November 2, 11
Important Methods




Wednesday, November 2, 11
onBrowserEvent()
       Gets called when an event for this cell occurred
       Gets passed in the parent Element
       Cell on its own does not know anything where it is displayed
       One Cell can be displayed in many places




             void onBrowserEvent(Context context, Element parent, C value,
                 NativeEvent event, ValueUpdater<C> valueUpdater);




Wednesday, November 2, 11
render()
       Called when a Cell should be rendered
       The output should be written to the SafeHtmlBuilder




                void render(Context context, C value, SafeHtmlBuilder sb);




Wednesday, November 2, 11
getConsumedEvents()
       Returns the events this cell requires
       Cannot change in the lifecycle of a Cell




                            Set<String> getConsumedEvents();




Wednesday, November 2, 11
Implementation




Wednesday, November 2, 11
The Class
       Extending AbstractCell
       Implementing the Cell interface directly works too



                        public class SquareCell extends AbstractCell<Data> {

                        }




Wednesday, November 2, 11
Constructor
       Defining the events this cell listens to




                            public SquareCell() {
                              super("click", "mouseover", "mouseout");
                            }




Wednesday, November 2, 11
onBrowserEvent()
       Contains our event handling logic

                public void onBrowserEvent(Context context, Element parent, Data value,
                    NativeEvent event, ValueUpdater<Data> valueUpdater) {
                  Element t = parent.getFirstChildElement();
                  Element target = event.getEventTarget().cast();
                  if (!t.isOrHasChild(target)) {
                    return;
                  }

                    if ("mouseout".equals(event.getType())) {
                      onMouseOut(context, parent, value, event);
                    } else if ("mouseover".equals(event.getType())) {
                      onMouseOver(context, parent, value, event);
                    } else if ("click".equals(event.getType())) {
                      onClick(context, parent, value, event);
                    }
                }
Wednesday, November 2, 11
onMouseOver()
       getRelatedEventTarget returns the Element coming from
       Setting the mouse over value



         private void onMouseOver(Context context, Element parent, Data value,
             NativeEvent event) {
           Element fc = parent.getFirstChildElement();
           EventTarget t = event.getRelatedEventTarget();
           if (t == null || (Element.is(t) && !fc.isOrHasChild(Element.as(t)))) {
             String s = SafeHtmlUtils.fromString(value.getMouseOverName()).asString();
             getContentElement(parent).setInnerHTML(s);
           }
         }




Wednesday, November 2, 11
onMouseOut()
       getRelatedEventTarget returns the Element moving to
       Clearing the background color
       Setting the standard value again
          private void onMouseOut(Context context, Element parent, Data value,
              NativeEvent event) {
            Element fc = parent.getFirstChildElement();
            EventTarget t = event.getRelatedEventTarget();
            if (t == null || (Element.is(t) && !fc.isOrHasChild(Element.as(t)))) {
              fc.getStyle().clearBackgroundColor();
              String s = SafeHtmlUtils.fromString(value.getName()).asString();
              getContentElement(parent).setInnerHTML(s);
            }
          }




Wednesday, November 2, 11
onClick()
       Sets the different background color




           private void onClick(Context context, Element parent, Data value,
               NativeEvent event) {
             parent.getFirstChildElement().getStyle().setBackgroundColor("red");
           }




Wednesday, November 2, 11
Demonstration




Wednesday, November 2, 11
Questions




Wednesday, November 2, 11
Thank You!




Wednesday, November 2, 11

Creating Ext GWT Extensions and Components

  • 1.
  • 2.
    CUSTOM COMPONENTS Sven Brunken sven@sencha.com @svenbrunken Wednesday, November 2, 11
  • 3.
    Overview Widget vs Component Important methods of the Widget class When to use the Cell class? Important methods of the Cell class Questions Wednesday, November 2, 11
  • 4.
    Which Class ToStart From? Wednesday, November 2, 11
  • 5.
    Widget Build on top of a DOM Element Listens to browser events Needs to be attached and detached for event handling Does not solve the different sizing boxes Can fire custom events through its HandlerManager Wednesday, November 2, 11
  • 6.
    Component Extends the Widget class and so inherits all its features Solves the different sizing boxes Can be disabled directly Can be positioned Wednesday, November 2, 11
  • 7.
  • 8.
    sinkEvents() Defines which events can be listened to Events not sunk cannot be listened to public void sinkEvents(int eventBitsToAdd) { if (isOrWasAttached()) { DOM.sinkEvents(getElement(), eventBitsToAdd|DOM.getEventsSunk(getElement())); } else { eventsToSink |= eventBitsToAdd; } } Wednesday, November 2, 11
  • 9.
    onAttach() Removes the event listener Mandatory to enable browser event handling Attaches the event listener of all its children widgets protected void onAttach() { attached = true; DOM.setEventListener(getElement(), this); int bitsToAdd = eventsToSink; eventsToSink = -1; if (bitsToAdd > 0) { sinkEvents(bitsToAdd); } doAttachChildren(); onLoad(); AttachEvent.fire(this, true); } Wednesday, November 2, 11
  • 10.
    onDetach() Removes the event listener added from onAttach() Browser events are no longer handled for this Widget Prevents memory leaks Detaches the event listener for all its children widgets protected void onDetach() { try { onUnload(); AttachEvent.fire(this, false); } finally { try { doDetachChildren(); } finally { DOM.setEventListener(getElement(), null); attached = false; } } } Wednesday, November 2, 11
  • 11.
    fireEvent() Fires a custom event through the HandlerManager Other classes could listen to these events public void fireEvent(GwtEvent<?> event) { if (handlerManager != null) { handlerManager.fireEvent(event); } } Wednesday, November 2, 11
  • 12.
    onBrowserEvent() Only called when a Widget is attached Gets called with the browser event that occurred Refires the browser event through the HandlerManager public void onBrowserEvent(Event event) { DomEvent.fireNativeEvent(event, this, this.getElement()); } Wednesday, November 2, 11
  • 13.
    setElement() Sets the element for this Widget Mandatory to be called An Element can only be set once and not changed Needs to be called before calling getElement() protected void setElement(Element elem) { assert (element == null) : SETELEMENT_TWICE_ERROR; this.element = elem; } Wednesday, November 2, 11
  • 14.
  • 15.
    Gathering Information What is the purpose of my custom widget? Which browser events are required? Can I extend an already existing class? Do I understand all my requirements? Wednesday, November 2, 11
  • 16.
  • 17.
    The Class Extending Component to overcome different sizing models public class SquareWidget extends Component { } Wednesday, November 2, 11
  • 18.
    Constructor Setting the Element Defining the events we want to listen to public SquareWidget(Data data) { this.data = data; SquareWidgetTemplate t = GWT.create(SquareWidgetTemplate.class); setElement(XDOM.create(t.render(data))); sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT | Event.ONCLICK); setPixelSize(100, 100); } Wednesday, November 2, 11
  • 19.
    onBrowserEvent() Contains our event handling logic Should call the super method @Override public void onBrowserEvent(Event event) { super.onBrowserEvent(event); if (event.getTypeInt() == Event.ONMOUSEOUT) { onMouseOut(event); } else if (event.getTypeInt() == Event.ONMOUSEOVER) { onMouseOver(event); } else if (event.getTypeInt() == Event.ONCLICK) { onClick(event); } } Wednesday, November 2, 11
  • 20.
    onMouseOver() getRelatedEventTarget returns the Element coming from Setting the mouse over value private void onMouseOver(Event event) { EventTarget t = event.getRelatedEventTarget(); if (t == null || Element.is(t) && !getElement().isOrHasChild(Element.as(t))) { String s = SafeHtmlUtils.fromString(data.getMouseOverName()).asString(); getContentElement().setInnerHTML(s); } } Wednesday, November 2, 11
  • 21.
    onMouseOut() getRelatedEventTarget returns the Element moving to Clearing the background color Setting the standard value again private void onMouseOut(Event event) { EventTarget t = event.getRelatedEventTarget(); if (t == null || (Element.is(t) && !getElement().isOrHasChild(Element.as(t)))) { getElement().getStyle().clearBackgroundColor(); String s = SafeHtmlUtils.fromString(data.getName()).asString(); getContentElement().setInnerHTML(s); } } Wednesday, November 2, 11
  • 22.
    onClick() Sets the different background color private void onClick(Event event) { getElement().getStyle().setBackgroundColor("red"); } Wednesday, November 2, 11
  • 23.
  • 24.
    But, Do WeReally Require a Widget? Wednesday, November 2, 11
  • 25.
    Introducing Cell Cells can handle browser events Cells can be used in data components Widgets cannot be used there Cells render a lot faster Wednesday, November 2, 11
  • 26.
    Context of theCell Contains the relevant row and column index Important when used in data widgets Contains the key representing the value Wednesday, November 2, 11
  • 27.
  • 28.
    onBrowserEvent() Gets called when an event for this cell occurred Gets passed in the parent Element Cell on its own does not know anything where it is displayed One Cell can be displayed in many places void onBrowserEvent(Context context, Element parent, C value, NativeEvent event, ValueUpdater<C> valueUpdater); Wednesday, November 2, 11
  • 29.
    render() Called when a Cell should be rendered The output should be written to the SafeHtmlBuilder void render(Context context, C value, SafeHtmlBuilder sb); Wednesday, November 2, 11
  • 30.
    getConsumedEvents() Returns the events this cell requires Cannot change in the lifecycle of a Cell Set<String> getConsumedEvents(); Wednesday, November 2, 11
  • 31.
  • 32.
    The Class Extending AbstractCell Implementing the Cell interface directly works too public class SquareCell extends AbstractCell<Data> { } Wednesday, November 2, 11
  • 33.
    Constructor Defining the events this cell listens to public SquareCell() { super("click", "mouseover", "mouseout"); } Wednesday, November 2, 11
  • 34.
    onBrowserEvent() Contains our event handling logic public void onBrowserEvent(Context context, Element parent, Data value, NativeEvent event, ValueUpdater<Data> valueUpdater) { Element t = parent.getFirstChildElement(); Element target = event.getEventTarget().cast(); if (!t.isOrHasChild(target)) { return; } if ("mouseout".equals(event.getType())) { onMouseOut(context, parent, value, event); } else if ("mouseover".equals(event.getType())) { onMouseOver(context, parent, value, event); } else if ("click".equals(event.getType())) { onClick(context, parent, value, event); } } Wednesday, November 2, 11
  • 35.
    onMouseOver() getRelatedEventTarget returns the Element coming from Setting the mouse over value private void onMouseOver(Context context, Element parent, Data value, NativeEvent event) { Element fc = parent.getFirstChildElement(); EventTarget t = event.getRelatedEventTarget(); if (t == null || (Element.is(t) && !fc.isOrHasChild(Element.as(t)))) { String s = SafeHtmlUtils.fromString(value.getMouseOverName()).asString(); getContentElement(parent).setInnerHTML(s); } } Wednesday, November 2, 11
  • 36.
    onMouseOut() getRelatedEventTarget returns the Element moving to Clearing the background color Setting the standard value again private void onMouseOut(Context context, Element parent, Data value, NativeEvent event) { Element fc = parent.getFirstChildElement(); EventTarget t = event.getRelatedEventTarget(); if (t == null || (Element.is(t) && !fc.isOrHasChild(Element.as(t)))) { fc.getStyle().clearBackgroundColor(); String s = SafeHtmlUtils.fromString(value.getName()).asString(); getContentElement(parent).setInnerHTML(s); } } Wednesday, November 2, 11
  • 37.
    onClick() Sets the different background color private void onClick(Context context, Element parent, Data value, NativeEvent event) { parent.getFirstChildElement().getStyle().setBackgroundColor("red"); } Wednesday, November 2, 11
  • 38.
  • 39.
  • 40.