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

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