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.

JavaScriptRendererConnector.java 9.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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.connectors;
  17. import java.util.ArrayList;
  18. import java.util.Collection;
  19. import com.google.gwt.core.client.JavaScriptObject;
  20. import com.google.gwt.core.client.JsArrayString;
  21. import com.google.gwt.dom.client.NativeEvent;
  22. import com.vaadin.client.JavaScriptConnectorHelper;
  23. import com.vaadin.client.Util;
  24. import com.vaadin.client.communication.HasJavaScriptConnectorHelper;
  25. import com.vaadin.client.connectors.grid.AbstractGridRendererConnector;
  26. import com.vaadin.client.connectors.grid.GridConnector;
  27. import com.vaadin.client.renderers.ComplexRenderer;
  28. import com.vaadin.client.renderers.Renderer;
  29. import com.vaadin.client.widget.grid.CellReference;
  30. import com.vaadin.client.widget.grid.RendererCellReference;
  31. import com.vaadin.shared.JavaScriptExtensionState;
  32. import com.vaadin.shared.ui.Connect;
  33. import elemental.json.JsonObject;
  34. import elemental.json.JsonValue;
  35. /**
  36. * Connector for server-side renderer implemented using JavaScript.
  37. *
  38. * @since 7.4
  39. * @author Vaadin Ltd
  40. */
  41. // This is really typed to <JsonValue>, but because of the way native strings
  42. // are not always instanceof JsonValue, we need to accept Object
  43. @Connect(com.vaadin.ui.renderers.AbstractJavaScriptRenderer.class)
  44. public class JavaScriptRendererConnector
  45. extends AbstractGridRendererConnector<Object>
  46. implements HasJavaScriptConnectorHelper {
  47. private final JavaScriptConnectorHelper helper = new JavaScriptConnectorHelper(
  48. this);
  49. private final JavaScriptObject cellReferenceWrapper = createCellReferenceWrapper();
  50. @Override
  51. protected void init() {
  52. super.init();
  53. helper.init();
  54. addGetRowKey(helper.getConnectorWrapper());
  55. }
  56. private static native JavaScriptObject createCellReferenceWrapper()
  57. /*-{
  58. var reference = {};
  59. var setProperty = function(name, getter, setter) {
  60. var descriptor = {
  61. get: getter
  62. }
  63. if (setter) {
  64. descriptor.set = setter;
  65. }
  66. Object.defineProperty(reference, name, descriptor);
  67. };
  68. setProperty("element", function() {
  69. return reference.target.@CellReference::getElement()();
  70. }, null);
  71. setProperty("rowIndex", function() {
  72. return reference.target.@CellReference::getRowIndex()();
  73. }, null);
  74. setProperty("columnIndex", function() {
  75. return reference.target.@CellReference::getColumnIndex()();
  76. }, null);
  77. setProperty("colSpan", function() {
  78. return reference.target.@RendererCellReference::getColSpan()();
  79. }, function(colSpan) {
  80. reference.target.@RendererCellReference::setColSpan(*)(colSpan);
  81. });
  82. return reference;
  83. }-*/;
  84. @Override
  85. public JavaScriptExtensionState getState() {
  86. return (JavaScriptExtensionState) super.getState();
  87. }
  88. private native void addGetRowKey(JavaScriptObject wrapper)
  89. /*-{
  90. var self = this;
  91. wrapper.getRowKey = $entry(function(rowIndex) {
  92. return @JavaScriptRendererConnector::findRowKey(*)(self, rowIndex);
  93. });
  94. }-*/;
  95. private static String findRowKey(JavaScriptRendererConnector connector,
  96. int rowIndex) {
  97. GridConnector gc = connector.getGridConnector();
  98. JsonObject row = gc.getWidget().getDataSource().getRow(rowIndex);
  99. return connector.getRowKey(row);
  100. }
  101. private boolean hasFunction(String name) {
  102. return hasFunction(helper.getConnectorWrapper(), name);
  103. }
  104. private static native boolean hasFunction(JavaScriptObject wrapper,
  105. String name)
  106. /*-{
  107. return typeof wrapper[name] === 'function';
  108. }-*/;
  109. @Override
  110. protected Renderer<Object> createRenderer() {
  111. helper.ensureJavascriptInited();
  112. if (!hasFunction("render")) {
  113. throw new RuntimeException(
  114. "JavaScriptRenderer " + helper.getInitFunctionName()
  115. + " must have a function named 'render'");
  116. }
  117. final boolean hasInit = hasFunction("init");
  118. final boolean hasDestroy = hasFunction("destroy");
  119. final boolean hasOnActivate = hasFunction("onActivate");
  120. final boolean hasGetConsumedEvents = hasFunction("getConsumedEvents");
  121. final boolean hasOnBrowserEvent = hasFunction("onBrowserEvent");
  122. return new ComplexRenderer<Object>() {
  123. @Override
  124. public void render(RendererCellReference cell, Object data) {
  125. if (data instanceof JsonValue) {
  126. data = Util.json2jso((JsonValue) data);
  127. }
  128. render(helper.getConnectorWrapper(), getJsCell(cell), data);
  129. }
  130. private JavaScriptObject getJsCell(CellReference<?> cell) {
  131. updateCellReference(cellReferenceWrapper, cell);
  132. return cellReferenceWrapper;
  133. }
  134. public native void render(JavaScriptObject wrapper,
  135. JavaScriptObject cell, Object data)
  136. /*-{
  137. wrapper.render(cell, data);
  138. }-*/;
  139. @Override
  140. public void init(RendererCellReference cell) {
  141. if (hasInit) {
  142. init(helper.getConnectorWrapper(), getJsCell(cell));
  143. }
  144. }
  145. private native void init(JavaScriptObject wrapper,
  146. JavaScriptObject cell)
  147. /*-{
  148. wrapper.init(cell);
  149. }-*/;
  150. private native void updateCellReference(
  151. JavaScriptObject cellWrapper, CellReference<?> target)
  152. /*-{
  153. cellWrapper.target = target;
  154. }-*/;
  155. @Override
  156. public void destroy(RendererCellReference cell) {
  157. if (hasDestroy) {
  158. destory(helper.getConnectorWrapper(), getJsCell(cell));
  159. } else {
  160. super.destroy(cell);
  161. }
  162. }
  163. private native void destory(JavaScriptObject wrapper,
  164. JavaScriptObject cell)
  165. /*-{
  166. wrapper.destory(cell);
  167. }-*/;
  168. @Override
  169. public boolean onActivate(CellReference<?> cell) {
  170. if (hasOnActivate) {
  171. return onActivate(helper.getConnectorWrapper(),
  172. getJsCell(cell));
  173. } else {
  174. return super.onActivate(cell);
  175. }
  176. }
  177. private native boolean onActivate(JavaScriptObject wrapper,
  178. JavaScriptObject cell)
  179. /*-{
  180. return !!wrapper.onActivate(cell);
  181. }-*/;
  182. @Override
  183. public Collection<String> getConsumedEvents() {
  184. if (hasGetConsumedEvents) {
  185. JsArrayString events = getConsumedEvents(
  186. helper.getConnectorWrapper());
  187. ArrayList<String> list = new ArrayList<>(events.length());
  188. for (int i = 0; i < events.length(); i++) {
  189. list.add(events.get(i));
  190. }
  191. return list;
  192. } else {
  193. return super.getConsumedEvents();
  194. }
  195. }
  196. private native JsArrayString getConsumedEvents(
  197. JavaScriptObject wrapper)
  198. /*-{
  199. var rawEvents = wrapper.getConsumedEvents();
  200. var events = [];
  201. for(var i = 0; i < rawEvents.length; i++) {
  202. events[i] = ""+rawEvents[i];
  203. }
  204. return events;
  205. }-*/;
  206. @Override
  207. public boolean onBrowserEvent(CellReference<?> cell,
  208. NativeEvent event) {
  209. if (hasOnBrowserEvent) {
  210. return onBrowserEvent(helper.getConnectorWrapper(),
  211. getJsCell(cell), event);
  212. } else {
  213. return super.onBrowserEvent(cell, event);
  214. }
  215. }
  216. private native boolean onBrowserEvent(JavaScriptObject wrapper,
  217. JavaScriptObject cell, NativeEvent event)
  218. /*-{
  219. return !!wrapper.onBrowserEvent(cell, event);
  220. }-*/;
  221. };
  222. }
  223. @Override
  224. public Object decode(JsonValue value) {
  225. // Let the js logic decode the raw json that the server sent
  226. return value;
  227. }
  228. @Override
  229. public void onUnregister() {
  230. super.onUnregister();
  231. helper.onUnregister();
  232. }
  233. @Override
  234. public JavaScriptConnectorHelper getJavascriptConnectorHelper() {
  235. return helper;
  236. }
  237. }