You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

gwt-extension.asciidoc 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. ---
  2. title: Component and UI Extensions
  3. order: 7
  4. layout: page
  5. ---
  6. [[gwt.extension]]
  7. = Component and UI Extensions
  8. Adding features to existing components by extending them by inheritance creates
  9. a problem when you want to combine such features. For example, one add-on could
  10. add spell-check to a [classname]#TextField#, while another could add client-side
  11. validation. Combining such add-on features would be difficult if not impossible.
  12. You might also want to add a feature to several or even to all components, but
  13. extending all of them by inheritance is not really an option. Vaadin includes a
  14. component plug-in mechanism for these purposes. Such plug-ins are simply called
  15. __extensions__.
  16. Also a UI can be extended in a similar fashion. In fact, some Vaadin features
  17. such as the JavaScript execution are UI extensions.
  18. Implementing an extension requires defining a server-side extension class and a
  19. client-side connector. An extension can have a shared state with the connector
  20. and use RPC, just like a component could.
  21. [[gwt.extension.server-side]]
  22. == Server-Side Extension API
  23. The server-side API for an extension consists of class that extends (in the Java
  24. sense) the [classname]#AbstractExtension# class. It typically has an
  25. __extend()__ method, a constructor, or a static helper method that takes the
  26. extended component or UI as a parameter and passes it to __super.extend()__.
  27. For example, let us have a trivial example with an extension that takes no
  28. special parameters, and illustrates the three alternative APIs:
  29. ----
  30. public class CapsLockWarning extends AbstractExtension {
  31. // You could pass it in the constructor
  32. public CapsLockWarning(PasswordField field) {
  33. super.extend(field);
  34. }
  35. // Or in an extend() method
  36. public void extend(PasswordField field) {
  37. super.extend(field);
  38. }
  39. // Or with a static helper
  40. public static addTo(PasswordField field) {
  41. new CapsLockWarning().extend(field);
  42. }
  43. }
  44. ----
  45. The extension could then be added to a component as follows:
  46. ----
  47. PasswordField password = new PasswordField("Give it");
  48. // Use the constructor
  49. new CapsLockWarning(password);
  50. // ... or with the extend() method
  51. new CapsLockWarning().extend(password);
  52. // ... or with the static helper
  53. CapsLockWarning.addTo(password);
  54. layout.addComponent(password);
  55. ----
  56. Adding a feature in such a "reverse" way is a bit unusual in the Vaadin API, but
  57. allows type safety for extensions, as the method can limit the target type to
  58. which the extension can be applied, and whether it is a regular component or a
  59. UI.
  60. [[gwt.extension.connector]]
  61. == Extension Connectors
  62. An extension does not have a corresponding widget on the client-side, but only
  63. an extension connector that extends the [classname]#AbstractExtensionConnector#
  64. class. The server-side extension class is specified with a
  65. [literal]#++@Connect++# annotation, just like in component connectors.
  66. An extension connector needs to implement the [methodname]#extend()# method,
  67. which allows hooking to the extended component. The normal extension mechanism
  68. is to modify the extended component as needed and add event handlers to it to
  69. handle user interaction. An extension connector can share a state with the
  70. server-side extension as well as make RPC calls, just like with components.
  71. In the following example, we implement a "Caps Lock warning" extension. It
  72. listens for changes in Caps Lock state and displays a floating warning element
  73. over the extended component if the Caps Lock is on.
  74. ----
  75. @Connect(CapsLockWarning.class)
  76. public class CapsLockWarningConnector
  77. extends AbstractExtensionConnector {
  78. @Override
  79. protected void extend(ServerConnector target) {
  80. // Get the extended widget
  81. final Widget pw =
  82. ((ComponentConnector) target).getWidget();
  83. // Preparations for the added feature
  84. final VOverlay warning = new VOverlay();
  85. warning.setOwner(pw);
  86. warning.add(new HTML("Caps Lock is enabled!"));
  87. // Add an event handler
  88. pw.addDomHandler(new KeyPressHandler() {
  89. public void onKeyPress(KeyPressEvent event) {
  90. if (isEnabled() && isCapsLockOn(event)) {
  91. warning.showRelativeTo(passwordWidget);
  92. } else {
  93. warning.hide();
  94. }
  95. }
  96. }, KeyPressEvent.getType());
  97. }
  98. private boolean isCapsLockOn(KeyPressEvent e) {
  99. return e.isShiftKeyDown() ^
  100. Character.isUpperCase(e.getCharCode());
  101. }
  102. }
  103. ----
  104. The [methodname]#extend()# method gets the connector of the extended component
  105. as the parameter, in the above example a [classname]#PasswordFieldConnector#. It
  106. can access the widget with the [methodname]#getWidget()#.
  107. An extension connector needs to be included in a widget set. The class must
  108. therefore be defined under the [filename]#client# package of a widget set, just
  109. like with component connectors.