/*
* Copyright 2000-2022 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.ui.renderers;
import com.vaadin.server.AbstractJavaScriptExtension;
import com.vaadin.server.JavaScriptCallbackHelper;
import com.vaadin.server.JsonCodec;
import com.vaadin.shared.JavaScriptExtensionState;
import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.ui.JavaScriptFunction;
import elemental.json.Json;
import elemental.json.JsonValue;
/**
* Base class for Renderers with all client-side logic implemented using
* JavaScript.
*
* When a new JavaScript renderer is initialized in the browser, the framework
* will look for a globally defined JavaScript function that will initialize the
* renderer. The name of the initialization function is formed by replacing .
* with _ in the name of the server-side class. If no such function is defined,
* each super class is used in turn until a match is found. The framework will
* thus first attempt with com_example_MyRenderer for the
* server-side
* com.example.MyRenderer extends AbstractJavaScriptRenderer class.
* If MyRenderer instead extends com.example.SuperRenderer , then
* com_example_SuperRenderer will also be attempted if
* com_example_MyRenderer has not been defined.
*
*
* In addition to the general JavaScript extension functionality explained in
* {@link AbstractJavaScriptExtension}, this class also provides some
* functionality specific for renderers.
*
* The initialization function will be called with this pointing to
* a connector wrapper object providing integration to Vaadin. Please note that
* in JavaScript, this is not necessarily defined inside callback
* functions and it might therefore be necessary to assign the reference to a
* separate variable, e.g. var self = this;. In addition to the
* extension functions described for {@link AbstractJavaScriptExtension}, the
* connector wrapper object also provides this function:
*
*
getRowKey(rowIndex) - Gets a unique identifier for the row
* at the given index. This identifier can be used on the server to retrieve the
* corresponding ItemId using {@link #getItemId(String)}.
*
* The connector wrapper also supports these special functions that can be
* implemented by the connector:
*
*
render(cell, data) - Callback for rendering the given data
* into the given cell. The structure of cell and data are described in separate
* sections below. The renderer is required to implement this function.
* Corresponds to
* {@link com.vaadin.client.renderers.Renderer#render(com.vaadin.client.widget.grid.RendererCellReference, Object)}
* .
*
init(cell) - Prepares a cell for rendering. Corresponds to
* {@link com.vaadin.client.renderers.ComplexRenderer#init(com.vaadin.client.widget.grid.RendererCellReference)}
* .
*
destroy(cell) - Allows the renderer to release resources
* allocate for a cell that will no longer be used. Corresponds to
* {@link com.vaadin.client.renderers.ComplexRenderer#destroy(com.vaadin.client.widget.grid.RendererCellReference)}
* .
*
onActivate(cell) - Called when the cell is activated by the
* user e.g. by double clicking on the cell or pressing enter with the cell
* focused. Corresponds to
* {@link com.vaadin.client.renderers.ComplexRenderer#onActivate(com.vaadin.client.widget.grid.CellReference)}
* .
*
getConsumedEvents() - Returns a JavaScript array of event
* names that should cause onBrowserEvent to be invoked whenever an event is
* fired for a cell managed by this renderer. Corresponds to
* {@link com.vaadin.client.renderers.ComplexRenderer#getConsumedEvents()}.
*
onBrowserEvent(cell, event) - Called by Grid when an event
* of a type returned by getConsumedEvents is fired for a cell managed by this
* renderer. Corresponds to
* {@link com.vaadin.client.renderers.ComplexRenderer#onBrowserEvent(com.vaadin.client.widget.grid.CellReference, com.google.gwt.dom.client.NativeEvent)}
* .
*
*
*
* The cell object passed to functions defined by the renderer has these
* properties:
*
*
element - The DOM element corresponding to this cell.
* Readonly.
*
rowIndex - The current index of the row of this cell.
* Readonly.
*
columnIndex - The current index of the column of this cell.
* Readonly.
*
colSpan - The number of columns spanned by this cell. Only
* supported in the object passed to the render function - other
* functions should not use the property. Readable and writable.
*
*
* @param
* the grid type this renderer can be attached to
* @param
* the type this renderer knows how to present
*
* @author Vaadin Ltd
* @since 8.0
*/
public abstract class AbstractJavaScriptRenderer
extends AbstractRenderer {
private JavaScriptCallbackHelper callbackHelper = new JavaScriptCallbackHelper(
this);
protected AbstractJavaScriptRenderer(Class presentationType,
String nullRepresentation) {
super(presentationType, nullRepresentation);
}
protected AbstractJavaScriptRenderer(Class presentationType) {
super(presentationType, null);
}
@Override
protected void registerRpc(R implementation,
Class rpcInterfaceType) {
super.registerRpc(implementation, rpcInterfaceType);
callbackHelper.registerRpc(rpcInterfaceType);
}
/**
* Register a {@link JavaScriptFunction} that can be called from the
* JavaScript using the provided name. A JavaScript function with the
* provided name will be added to the connector wrapper object (initially
* available as this). Calling that JavaScript function will
* cause the call method in the registered {@link JavaScriptFunction} to be
* invoked with the same arguments.
*
* @param functionName
* the name that should be used for client-side callback
* @param function
* the {@link JavaScriptFunction} object that will be invoked
* when the JavaScript function is called
*/
protected void addFunction(String functionName,
JavaScriptFunction function) {
callbackHelper.registerCallback(functionName, function);
}
/**
* Invoke a named function that the connector JavaScript has added to the
* JavaScript connector wrapper object. The arguments can be any boxed
* primitive type, String, {@link JsonValue} or arrays of any other
* supported type. Complex types (e.g. List, Set, Map, Connector or any
* JavaBean type) must be explicitly serialized to a {@link JsonValue}
* before sending. This can be done either with
* {@link JsonCodec#encode(Object, JsonValue, java.lang.reflect.Type, com.vaadin.ui.ConnectorTracker)}
* or using the factory methods in {@link Json}.
*
* @param name
* the name of the function
* @param arguments
* function arguments
*/
protected void callFunction(String name, Object... arguments) {
callbackHelper.invokeCallback(name, arguments);
}
@Override
protected JavaScriptExtensionState getState() {
return (JavaScriptExtensionState) super.getState();
}
@Override
protected JavaScriptExtensionState getState(boolean markAsDirty) {
return (JavaScriptExtensionState) super.getState(markAsDirty);
}
}
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'none'
Content-Type: text/plain; charset=UTF-8
Content-Length: 5736
Content-Disposition: inline; filename="AbstractRenderer.java"
Last-Modified: Sun, 05 Jan 2025 10:35:46 GMT
Expires: Sun, 05 Jan 2025 10:40:46 GMT
ETag: "a0baf1c523c8a26d27866a454046e82be331f34f"
/*
* Copyright 2000-2022 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.ui.renderers;
import java.util.Objects;
import com.vaadin.server.AbstractClientConnector;
import com.vaadin.server.AbstractExtension;
import com.vaadin.server.JsonCodec;
import com.vaadin.shared.ui.grid.renderers.AbstractRendererState;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.Column;
import com.vaadin.ui.renderers.ClickableRenderer.RendererClickEvent;
import elemental.json.JsonValue;
/**
* An abstract base class for server-side
* {@link com.vaadin.ui.renderers.Renderer Grid renderers}.
*
*
* This class currently extends the AbstractExtension superclass, but this fact
* should be regarded as an implementation detail and subject to change in a
* future major or minor Vaadin version.
*
* @param
* the grid type this renderer can be attached to
* @param
* the type this renderer knows how to present
* @since 8.0
*/
public abstract class AbstractRenderer extends AbstractExtension
implements Renderer {
private final Class presentationType;
private final String nullRepresentation;
/**
* Creates a new renderer with the given presentation type and null
* representation.
*
* @param presentationType
* the data type that this renderer displays, not
* null
* @param nullRepresentation
* a string that will be sent to the client instead of a regular
* value in case the actual cell value is null. May
* be null.
*/
protected AbstractRenderer(Class presentationType,
String nullRepresentation) {
Objects.requireNonNull(presentationType,
"Presentation type cannot be null");
this.presentationType = presentationType;
this.nullRepresentation = nullRepresentation;
}
/**
* Creates a new renderer with the given presentation type. No null
* representation will be used.
*
* @param presentationType
* the data type that this renderer displays, not
* null
*/
protected AbstractRenderer(Class presentationType) {
this(presentationType, null);
}
/**
* This method is inherited from AbstractExtension but should never be
* called directly with an AbstractRenderer.
*/
@Deprecated
@Override
@SuppressWarnings("rawtypes")
protected Class getSupportedParentType() {
return Column.class;
}
/**
* This method is inherited from AbstractExtension but should never be
* called directly with an AbstractRenderer.
*/
@Deprecated
@Override
protected void extend(AbstractClientConnector target) {
super.extend(target);
}
@Override
public Class getPresentationType() {
return presentationType;
}
@Override
public JsonValue encode(V value) {
if (value == null) {
return encode(getNullRepresentation(), String.class);
} else {
return encode(value, getPresentationType());
}
}
/**
* Null representation for the renderer.
*
* @return a textual representation of {@code null}
*/
protected String getNullRepresentation() {
return nullRepresentation;
}
/**
* Encodes the given value to JSON.
*
* This is a helper method that can be invoked by an {@link #encode(Object)
* encode(T)} override if serializing a value of type other than
* {@link #getPresentationType() the presentation type} is desired. For
* instance, a {@code Renderer} could first turn a date value into a
* formatted string and return {@code encode(dateString, String.class)}.
*
* @param value
* the value to be encoded
* @param type
* the type of the value
* @return a JSON representation of the given value
*/
protected JsonValue encode(U value, Class type) {
return JsonCodec
.encode(value, null, type, getUI().getConnectorTracker())
.getEncodedValue();
}
/**
* Gets the {@link Grid} this renderer is attached to. Used internally for
* indicating the source grid of possible events emitted by this renderer,
* such as {@link RendererClickEvent}s.
*
* @return the grid this renderer is attached to or {@code null} if
* unattached
*/
@SuppressWarnings("unchecked")
protected Grid getParentGrid() {
if (super.getParent() == null) {
return null;
}
return (Grid) super.getParent().getParent();
}
@Override
public Column getParent() {
return (Column) super.getParent();
}
@Override
protected AbstractRendererState getState() {
return (AbstractRendererState) super.getState();
}
@Override
protected AbstractRendererState getState(boolean markAsDirty) {
return (AbstractRendererState) super.getState(markAsDirty);
}
}
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'none'
Content-Type: text/plain; charset=UTF-8
Content-Length: 3421
Content-Disposition: inline; filename="ButtonRenderer.java"
Last-Modified: Sun, 05 Jan 2025 10:35:46 GMT
Expires: Sun, 05 Jan 2025 10:40:46 GMT
ETag: "fc1584a15c9064aa4a168c6b01282d8f0b0f95f6"
/*
* Copyright 2000-2022 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.ui.renderers;
import com.vaadin.shared.ui.grid.renderers.ButtonRendererState;
/**
* A Renderer that displays a button with a textual caption. The value of the
* corresponding property is used as the caption. Click listeners can be added
* to the renderer, invoked when any of the rendered buttons is clicked.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class ButtonRenderer extends ClickableRenderer {
/**
* Creates a new button renderer.
*
* @param nullRepresentation
* the textual representation of {@code null} value
*/
public ButtonRenderer(String nullRepresentation) {
super(String.class, nullRepresentation);
}
/**
* Creates a new button renderer and adds the given click listener to it.
*
* @param listener
* the click listener to register
* @param nullRepresentation
* the textual representation of {@code null} value
*/
public ButtonRenderer(RendererClickListener listener,
String nullRepresentation) {
this(nullRepresentation);
addClickListener(listener);
}
/**
* Creates a new button renderer.
*/
public ButtonRenderer() {
this("");
}
/**
* Creates a new button renderer and adds the given click listener to it.
*
* @param listener
* the click listener to register
*/
public ButtonRenderer(RendererClickListener listener) {
this(listener, "");
}
@Override
public String getNullRepresentation() {
return super.getNullRepresentation();
}
@Override
protected ButtonRendererState getState() {
return (ButtonRendererState) super.getState();
}
@Override
protected ButtonRendererState getState(boolean markAsDirty) {
return (ButtonRendererState) super.getState(markAsDirty);
}
/**
* Sets whether the data should be rendered as HTML (instead of text).
*
* By default everything is rendered as text.
*
* @param htmlContentAllowed
* true to render as HTML, false to
* render as text
*
* @since 8.0.3
*/
public void setHtmlContentAllowed(boolean htmlContentAllowed) {
getState().htmlContentAllowed = htmlContentAllowed;
}
/**
* Gets whether the data should be rendered as HTML (instead of text).
*
* By default everything is rendered as text.
*
* @return true if the renderer renders a HTML,
* false if the content is rendered as text
*
* @since 8.0.3
*/
public boolean isHtmlContentAllowed() {
return getState(false).htmlContentAllowed;
}
}
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'none'
Content-Type: text/plain; charset=UTF-8
Content-Length: 5780
Content-Disposition: inline; filename="ClickableRenderer.java"
Last-Modified: Sun, 05 Jan 2025 10:35:46 GMT
Expires: Sun, 05 Jan 2025 10:40:46 GMT
ETag: "1968d08aee30b895bd67d4cf6cd8d24f8ac96b0f"
/*
* Copyright 2000-2022 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.ui.renderers;
import java.lang.reflect.Method;
import com.vaadin.event.ConnectorEventListener;
import com.vaadin.event.MouseEvents.ClickEvent;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.grid.renderers.ClickableRendererState;
import com.vaadin.shared.ui.grid.renderers.RendererClickRpc;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.Column;
import com.vaadin.util.ReflectTools;
/**
* An abstract superclass for {@link Renderer}s that render clickable items.
* Click listeners can be added to a renderer to be notified when any of the
* rendered items is clicked.
*
* @param
* the type of the parent {@link Grid}
* @param
* the type presented by the renderer
*
* @since 7.4
* @author Vaadin Ltd
*/
public abstract class ClickableRenderer extends AbstractRenderer {
/**
* An interface for listening to {@link RendererClickEvent renderer click
* events}.
*
* @see ButtonRenderer#addClickListener(RendererClickListener)
*/
@FunctionalInterface
public interface RendererClickListener extends ConnectorEventListener {
static final Method CLICK_METHOD = ReflectTools.findMethod(
RendererClickListener.class, "click", RendererClickEvent.class);
/**
* Called when a rendered button is clicked.
*
* @param event
* the event representing the click
*/
void click(RendererClickEvent event);
}
/**
* An event fired when a clickable widget rendered by a ClickableRenderer is
* clicked.
*
* @param
* the item type associated with this click event
*/
public static class RendererClickEvent extends ClickEvent {
private final T item;
private final Column column;
protected RendererClickEvent(Grid source, T item,
Column column, MouseEventDetails mouseEventDetails) {
super(source, mouseEventDetails);
this.item = item;
this.column = column;
}
/**
* Returns the item of the row where the click event originated.
*
* @return the item of the clicked row
* @since 8.0
*/
public T getItem() {
return item;
}
/**
* Returns the {@link Column} where the click event originated.
*
* @return the column of the click event
*/
public Column getColumn() {
return column;
}
}
/**
* Creates a new clickable renderer with the given presentation type. No
* null representation will be used.
*
* @param presentationType
* the data type that this renderer displays, not
* null
*/
protected ClickableRenderer(Class presentationType) {
this(presentationType, null);
}
/**
* Creates a new clickable renderer with the given presentation type and
* null representation.
*
* @param presentationType
* the data type that this renderer displays, not
* null
* @param nullRepresentation
* a string that will be sent to the client instead of a regular
* value in case the actual cell value is null. May
* be null.
*/
protected ClickableRenderer(Class presentationType,
String nullRepresentation) {
super(presentationType, nullRepresentation);
registerRpc((RendererClickRpc) (String rowKey, String columnId,
MouseEventDetails mouseDetails) -> {
Grid grid = getParentGrid();
T item = grid.getDataCommunicator().getKeyMapper().get(rowKey);
Column column = getParent();
fireEvent(
new RendererClickEvent<>(grid, item, column, mouseDetails));
});
}
/**
* Adds a click listener to this button renderer. The listener is invoked
* every time one of the buttons rendered by this renderer is clicked.
*
* @param listener
* the click listener to be added, not null
* @since 8.0
*/
public Registration addClickListener(RendererClickListener listener) {
return addListener(RendererClickEvent.class, listener,
RendererClickListener.CLICK_METHOD);
}
/**
* Removes the given click listener from this renderer.
*
* @param listener
* the click listener to be removed
*/
@Deprecated
public void removeClickListener(RendererClickListener listener) {
removeListener(RendererClickEvent.class, listener);
}
@Override
protected ClickableRendererState getState() {
return (ClickableRendererState) super.getState();
}
@Override
protected ClickableRendererState getState(boolean markAsDirty) {
return (ClickableRendererState) super.getState(markAsDirty);
}
}
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'none'
Content-Type: text/plain; charset=UTF-8
Content-Length: 2481
Content-Disposition: inline; filename="ComponentRenderer.java"
Last-Modified: Sun, 05 Jan 2025 10:35:46 GMT
Expires: Sun, 05 Jan 2025 10:40:46 GMT
ETag: "f4febfa5c5ab80c8c62ce937dbd9958bed15dc3d"
/*
* Copyright 2000-2022 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.ui.renderers;
import com.vaadin.shared.ui.grid.renderers.ComponentRendererState;
import com.vaadin.ui.Component;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Label;
import elemental.json.Json;
import elemental.json.JsonValue;
/**
* A renderer for presenting Components.
*
* Note: The use of ComponentRenderer causes the Grid to
* generate components for all items currently available in the client-side.
* This means that a number of components is always generated and sent to the
* client. Using complex structures of many nested components might be heavy to
* generate and store, which will lead to performance problems.
*
* Note: Components will occasionally be generated again during
* runtime e.g. when selection changes. If your component has an internal state
* that is not stored into the object, you should reuse the same component
* instances.
*
* Example of how to add a {@link Label} component to {@link Grid}:
*
*
* Grid grid;
* grid.addColumn(person -> new Label(person.getFullName()),
* new ComponentRenderer()).setCaption("Full Name");
*
*
* @author Vaadin Ltd
* @since 8.1
*/
@SuppressWarnings("serial")
public class ComponentRenderer extends AbstractRenderer