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.

DragSourceExtensionConnector.java 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.client.extensions;
  17. import com.google.gwt.dom.client.DataTransfer;
  18. import com.google.gwt.dom.client.Element;
  19. import com.google.gwt.dom.client.NativeEvent;
  20. import com.google.gwt.user.client.ui.Widget;
  21. import com.vaadin.client.ComponentConnector;
  22. import com.vaadin.client.ServerConnector;
  23. import com.vaadin.event.dnd.DragSourceExtension;
  24. import com.vaadin.shared.ui.Connect;
  25. import com.vaadin.shared.ui.dnd.DragSourceRpc;
  26. import com.vaadin.shared.ui.dnd.DragSourceState;
  27. import com.vaadin.shared.ui.dnd.DropEffect;
  28. import elemental.events.Event;
  29. import elemental.events.EventListener;
  30. import elemental.events.EventTarget;
  31. /**
  32. * Extension to add drag source functionality to a widget for using HTML5 drag
  33. * and drop. Client side counterpart of {@link DragSourceExtension}.
  34. *
  35. * @author Vaadin Ltd
  36. * @since 8.1
  37. */
  38. @Connect(DragSourceExtension.class)
  39. public class DragSourceExtensionConnector extends AbstractExtensionConnector {
  40. private static final String CLASS_DRAGGABLE = "v-draggable";
  41. // Create event listeners
  42. private final EventListener dragStartListener = this::onDragStart;
  43. private final EventListener dragEndListener = this::onDragEnd;
  44. /**
  45. * Widget of the drag source component.
  46. */
  47. private Widget dragSourceWidget;
  48. @Override
  49. protected void extend(ServerConnector target) {
  50. dragSourceWidget = ((ComponentConnector) target).getWidget();
  51. setDraggable(getDraggableElement());
  52. addDragListeners(getDraggableElement());
  53. }
  54. /**
  55. * Sets the given element draggable and adds class name.
  56. *
  57. * @param element
  58. * Element to be set draggable.
  59. */
  60. protected void setDraggable(Element element) {
  61. element.setDraggable(Element.DRAGGABLE_TRUE);
  62. element.addClassName(CLASS_DRAGGABLE);
  63. }
  64. /**
  65. * Removes draggable and class name from the given element.
  66. *
  67. * @param element
  68. * Element to remove draggable from.
  69. */
  70. protected void removeDraggable(Element element) {
  71. element.setDraggable(Element.DRAGGABLE_FALSE);
  72. element.removeClassName(CLASS_DRAGGABLE);
  73. }
  74. /**
  75. * Adds dragstart and dragend event listeners to the given DOM element.
  76. *
  77. * @param element
  78. * DOM element to attach event listeners to.
  79. */
  80. protected void addDragListeners(Element element) {
  81. EventTarget target = element.cast();
  82. target.addEventListener(Event.DRAGSTART, dragStartListener);
  83. target.addEventListener(Event.DRAGEND, dragEndListener);
  84. }
  85. /**
  86. * Removes dragstart and dragend event listeners from the given DOM element.
  87. *
  88. * @param element
  89. * DOM element to remove event listeners from.
  90. */
  91. protected void removeDragListeners(Element element) {
  92. EventTarget target = element.cast();
  93. target.removeEventListener(Event.DRAGSTART, dragStartListener);
  94. target.removeEventListener(Event.DRAGEND, dragEndListener);
  95. }
  96. @Override
  97. public void onUnregister() {
  98. super.onUnregister();
  99. Element dragSource = getDraggableElement();
  100. removeDraggable(dragSource);
  101. removeDragListeners(dragSource);
  102. }
  103. /**
  104. * Event handler for the {@code dragstart} event. Called when {@code
  105. * dragstart} event occurs.
  106. *
  107. * @param event
  108. * browser event to be handled
  109. */
  110. protected void onDragStart(Event event) {
  111. // Convert elemental event to have access to dataTransfer
  112. NativeEvent nativeEvent = (NativeEvent) event;
  113. // Set effectAllowed parameter
  114. if (getState().effectAllowed != null) {
  115. setEffectAllowed(nativeEvent.getDataTransfer(),
  116. getState().effectAllowed.getValue());
  117. }
  118. // Set text data parameter
  119. nativeEvent.getDataTransfer().setData(DragSourceState.DATA_TYPE_TEXT,
  120. createDataTransferText(event));
  121. // Initiate firing server side dragstart event when there is a
  122. // DragStartListener attached on the server side
  123. if (hasEventListener(DragSourceState.EVENT_DRAGSTART)) {
  124. sendDragStartEventToServer(event);
  125. }
  126. // Stop event bubbling
  127. nativeEvent.stopPropagation();
  128. }
  129. /**
  130. * Creates data of type {@code "text"} for the {@code DataTransfer} object
  131. * of the given event.
  132. *
  133. * @param dragStartEvent
  134. * Event to set the data for.
  135. * @return Textual data to be set for the event or {@literal null}.
  136. */
  137. protected String createDataTransferText(Event dragStartEvent) {
  138. return getState().dataTransferText;
  139. }
  140. /**
  141. * Initiates a server RPC for the drag start event.
  142. * <p>
  143. * This method is called only if there is a server side drag start event
  144. * handler attached.
  145. *
  146. * @param dragStartEvent
  147. * Client side dragstart event.
  148. */
  149. protected void sendDragStartEventToServer(Event dragStartEvent) {
  150. getRpcProxy(DragSourceRpc.class).dragStart();
  151. }
  152. /**
  153. * Event handler for the {@code dragend} event. Called when {@code dragend}
  154. * event occurs.
  155. *
  156. * @param event
  157. * browser event to be handled
  158. */
  159. protected void onDragEnd(Event event) {
  160. // Initiate server start dragend event when there is a DragEndListener
  161. // attached on the server side
  162. if (hasEventListener(DragSourceState.EVENT_DRAGEND)) {
  163. String dropEffect = getDropEffect(
  164. ((NativeEvent) event).getDataTransfer());
  165. assert dropEffect != null : "Drop effect should never be null";
  166. sendDragEndEventToServer(event,
  167. DropEffect.valueOf(dropEffect.toUpperCase()));
  168. }
  169. }
  170. /**
  171. * Initiates a server RPC for the drag end event.
  172. *
  173. * @param dragEndEvent
  174. * Client side dragend event.
  175. * @param dropEffect
  176. * Drop effect of the dragend event, extracted from {@code
  177. * DataTransfer.dropEffect} parameter.
  178. */
  179. protected void sendDragEndEventToServer(Event dragEndEvent,
  180. DropEffect dropEffect) {
  181. getRpcProxy(DragSourceRpc.class).dragEnd(dropEffect);
  182. }
  183. /**
  184. * Finds the draggable element within the widget. By default, returns the
  185. * topmost element.
  186. *
  187. * @return the draggable element in the parent widget.
  188. */
  189. protected Element getDraggableElement() {
  190. return dragSourceWidget.getElement();
  191. }
  192. private native void setEffectAllowed(DataTransfer dataTransfer,
  193. String effectAllowed)/*-{
  194. dataTransfer.effectAllowed = effectAllowed;
  195. }-*/;
  196. private native String getDropEffect(DataTransfer dataTransfer)/*-{
  197. return dataTransfer.dropEffect;
  198. }-*/;
  199. @Override
  200. public DragSourceState getState() {
  201. return (DragSourceState) super.getState();
  202. }
  203. }