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

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