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 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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. [source,java]
  30. ----
  31. public class CapsLockWarning extends AbstractExtension {
  32. // You could pass it in the constructor
  33. public CapsLockWarning(PasswordField field) {
  34. super.extend(field);
  35. }
  36. // Or in an extend() method
  37. public void extend(PasswordField field) {
  38. super.extend(field);
  39. }
  40. // Or with a static helper
  41. public static void addTo(PasswordField field) {
  42. new CapsLockWarning().extend(field);
  43. }
  44. // NOTE: you only need one of the above, not all of them
  45. }
  46. ----
  47. The extension could then be added to a component as follows:
  48. [source,java]
  49. ----
  50. PasswordField password = new PasswordField("Give it");
  51. // Use the constructor
  52. new CapsLockWarning(password);
  53. // ... or with the extend() method
  54. new CapsLockWarning().extend(password);
  55. // ... or with the static helper
  56. CapsLockWarning.addTo(password);
  57. layout.addComponent(password);
  58. ----
  59. Adding a feature in such a "reverse" way is a bit unusual in the Vaadin API, but
  60. allows type safety for extensions, as the method can limit the target type to
  61. which the extension can be applied, and whether it is a regular component or a
  62. UI.
  63. [[gwt.extension.connector]]
  64. == Extension Connectors
  65. An extension does not have a corresponding widget on the client-side, but only
  66. an extension connector that extends the [classname]#AbstractExtensionConnector#
  67. class. The server-side extension class is specified with a
  68. [literal]#++@Connect++# annotation, just like in component connectors.
  69. An extension connector needs to implement the [methodname]#extend()# method,
  70. which allows hooking to the extended component. The normal extension mechanism
  71. is to modify the extended component as needed and add event handlers to it to
  72. handle user interaction. An extension connector can share a state with the
  73. server-side extension as well as make RPC calls, just like with components.
  74. In the following example, we implement a "Caps Lock warning" extension. It
  75. listens for changes in Caps Lock state and displays a floating warning element
  76. over the extended component if the Caps Lock is on.
  77. [source,java]
  78. ----
  79. @Connect(CapsLockWarning.class)
  80. public class CapsLockWarningConnector
  81. extends AbstractExtensionConnector {
  82. @Override
  83. protected void extend(ServerConnector target) {
  84. // Get the extended widget
  85. final Widget pw =
  86. ((ComponentConnector) target).getWidget();
  87. // Preparations for the added feature
  88. final VOverlay warning = new VOverlay();
  89. warning.setOwner(pw);
  90. warning.add(new HTML("Caps Lock is enabled!"));
  91. // Add an event handler
  92. pw.addDomHandler(new KeyPressHandler() {
  93. public void onKeyPress(KeyPressEvent event) {
  94. if (isEnabled() && isCapsLockOn(event)) {
  95. warning.showRelativeTo(passwordWidget);
  96. } else {
  97. warning.hide();
  98. }
  99. }
  100. }, KeyPressEvent.getType());
  101. }
  102. private boolean isCapsLockOn(KeyPressEvent e) {
  103. return e.isShiftKeyDown() ^
  104. Character.isUpperCase(e.getCharCode());
  105. }
  106. }
  107. ----
  108. The [methodname]#extend()# method gets the connector of the extended component
  109. as the parameter, in the above example a [classname]#PasswordFieldConnector#. It
  110. can access the widget with the [methodname]#getWidget()#.
  111. An extension connector needs to be included in a widget set. The class must
  112. therefore be defined under the [filename]#client# package of a widget set, just
  113. like with component connectors.