summaryrefslogtreecommitdiffstats
path: root/compatibility-client
diff options
context:
space:
mode:
authorPekka Hyvönen <pekka@vaadin.com>2016-10-06 16:19:53 +0300
committerVaadin Code Review <review@vaadin.com>2016-10-07 11:53:56 +0000
commit8cdaeb241a7e57561e69c2ee46d0dde54e591c45 (patch)
tree79a3ba8d1b16a686ce52eca3955df4b5a56b2e21 /compatibility-client
parentd383722053216a97bf75f9623a060a7edd48a01f (diff)
downloadvaadin-framework-8cdaeb241a7e57561e69c2ee46d0dde54e591c45.tar.gz
vaadin-framework-8cdaeb241a7e57561e69c2ee46d0dde54e591c45.zip
Add Upload to compatibility packages
Step 1 / 2 of adding a new Upload Component. Change-Id: I137d7952a540db18a616da4a944a2a44f27435da
Diffstat (limited to 'compatibility-client')
-rw-r--r--compatibility-client/src/main/java/com/vaadin/v7/client/ui/AbstractLegacyComponentConnector.java39
-rw-r--r--compatibility-client/src/main/java/com/vaadin/v7/client/ui/VUpload.java394
-rw-r--r--compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadConnector.java112
-rw-r--r--compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadIFrameOnloadStrategy.java39
-rw-r--r--compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadIFrameOnloadStrategyIE.java42
5 files changed, 626 insertions, 0 deletions
diff --git a/compatibility-client/src/main/java/com/vaadin/v7/client/ui/AbstractLegacyComponentConnector.java b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/AbstractLegacyComponentConnector.java
new file mode 100644
index 0000000000..a9fe473ad4
--- /dev/null
+++ b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/AbstractLegacyComponentConnector.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2000-2016 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.v7.client.ui;
+
+import com.vaadin.client.ui.AbstractComponentConnector;
+import com.vaadin.client.ui.AbstractConnector;
+import com.vaadin.shared.communication.ServerRpc;
+
+/**
+ * Legacy connector for Vaadin 7 compatibility connectors. Needed because
+ * <code>immediate</code> has been removed from {@link AbstractConnector} in
+ * Vaadin 8.
+ *
+ * @author Vaadin Ltd
+ * @since 8.0
+ */
+public class AbstractLegacyComponentConnector
+ extends AbstractComponentConnector {
+
+ // overridden to be visible to VUpload in the same package. Without making
+ // it public in VUploadConnector
+ @Override
+ protected <T extends ServerRpc> T getRpcProxy(Class<T> rpcInterface) {
+ return super.getRpcProxy(rpcInterface);
+ }
+}
diff --git a/compatibility-client/src/main/java/com/vaadin/v7/client/ui/VUpload.java b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/VUpload.java
new file mode 100644
index 0000000000..16108792b4
--- /dev/null
+++ b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/VUpload.java
@@ -0,0 +1,394 @@
+/*
+ * Copyright 2000-2016 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.v7.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.dom.client.DivElement;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.FormElement;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.ui.FileUpload;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.FormPanel;
+import com.google.gwt.user.client.ui.Hidden;
+import com.google.gwt.user.client.ui.Panel;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.BrowserInfo;
+import com.vaadin.client.ConnectorMap;
+import com.vaadin.client.StyleConstants;
+import com.vaadin.client.VConsole;
+import com.vaadin.client.ui.VButton;
+import com.vaadin.v7.client.ui.upload.UploadConnector;
+import com.vaadin.v7.client.ui.upload.UploadIFrameOnloadStrategy;
+import com.vaadin.v7.shared.ui.upload.UploadServerRpc;
+
+/**
+ *
+ * Note, we are not using GWT FormPanel as we want to listen submitcomplete
+ * events even though the upload component is already detached.
+ *
+ */
+public class VUpload extends SimplePanel {
+
+ private final class MyFileUpload extends FileUpload {
+ @Override
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ if (event.getTypeInt() == Event.ONCHANGE) {
+ if (immediate && fu.getFilename() != null
+ && !"".equals(fu.getFilename())) {
+ submit();
+ }
+ } else if (BrowserInfo.get().isIE()
+ && event.getTypeInt() == Event.ONFOCUS) {
+ // IE and user has clicked on hidden textarea part of upload
+ // field. Manually open file selector, other browsers do it by
+ // default.
+ fireNativeClick(fu.getElement());
+ // also remove focus to enable hack if user presses cancel
+ // button
+ fireNativeBlur(fu.getElement());
+ }
+ }
+ }
+
+ public static final String CLASSNAME = "v-upload";
+
+ /**
+ * FileUpload component that opens native OS dialog to select file.
+ * <p>
+ * For internal use only. May be removed or replaced in the future.
+ */
+ public FileUpload fu = new MyFileUpload();
+
+ Panel panel = new FlowPanel();
+
+ UploadIFrameOnloadStrategy onloadstrategy = GWT
+ .create(UploadIFrameOnloadStrategy.class);
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public ApplicationConnection client;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public String paintableId;
+
+ /**
+ * Button that initiates uploading.
+ * <p>
+ * For internal use only. May be removed or replaced in the future.
+ */
+ public final VButton submitButton;
+
+ /**
+ * When expecting big files, programmer may initiate some UI changes when
+ * uploading the file starts. Bit after submitting file we'll visit the
+ * server to check possible changes.
+ * <p>
+ * For internal use only. May be removed or replaced in the future.
+ */
+ public Timer t;
+
+ /**
+ * some browsers tries to send form twice if submit is called in button
+ * click handler, some don't submit at all without it, so we need to track
+ * if form is already being submitted
+ */
+ private boolean submitted = false;
+
+ private boolean enabled = true;
+
+ private boolean immediate;
+
+ private Hidden maxfilesize = new Hidden();
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public FormElement element;
+
+ private com.google.gwt.dom.client.Element synthesizedFrame;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public int nextUploadId;
+
+ public VUpload() {
+ super(com.google.gwt.dom.client.Document.get().createFormElement());
+
+ element = getElement().cast();
+ setEncoding(getElement(), FormPanel.ENCODING_MULTIPART);
+ element.setMethod(FormPanel.METHOD_POST);
+
+ setWidget(panel);
+ panel.add(maxfilesize);
+ panel.add(fu);
+ submitButton = new VButton();
+ submitButton.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ if (immediate) {
+ // fire click on upload (eg. focused button and hit space)
+ fireNativeClick(fu.getElement());
+ } else {
+ submit();
+ }
+ }
+ });
+ panel.add(submitButton);
+
+ setStyleName(CLASSNAME);
+ }
+
+ private static native void setEncoding(Element form, String encoding)
+ /*-{
+ form.enctype = encoding;
+ }-*/;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public void setImmediate(boolean booleanAttribute) {
+ if (immediate != booleanAttribute) {
+ immediate = booleanAttribute;
+ if (immediate) {
+ fu.sinkEvents(Event.ONCHANGE);
+ fu.sinkEvents(Event.ONFOCUS);
+ }
+ }
+ setStyleName(getElement(), CLASSNAME + "-immediate", immediate);
+ }
+
+ private static native void fireNativeClick(Element element)
+ /*-{
+ element.click();
+ }-*/;
+
+ private static native void fireNativeBlur(Element element)
+ /*-{
+ element.blur();
+ }-*/;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public void disableUpload() {
+ setEnabledForSubmitButton(false);
+ if (!submitted) {
+ // Cannot disable the fileupload while submitting or the file won't
+ // be submitted at all
+ fu.getElement().setPropertyBoolean("disabled", true);
+ }
+ enabled = false;
+ }
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public void enableUpload() {
+ setEnabledForSubmitButton(true);
+ fu.getElement().setPropertyBoolean("disabled", false);
+ enabled = true;
+ if (submitted) {
+ /*
+ * An old request is still in progress (most likely cancelled),
+ * ditching that target frame to make it possible to send a new
+ * file. A new target frame is created later."
+ */
+ cleanTargetFrame();
+ submitted = false;
+ }
+ }
+
+ private void setEnabledForSubmitButton(boolean enabled) {
+ submitButton.setEnabled(enabled);
+ submitButton.setStyleName(StyleConstants.DISABLED, !enabled);
+ }
+
+ /**
+ * Re-creates file input field and populates panel. This is needed as we
+ * want to clear existing values from our current file input field.
+ */
+ private void rebuildPanel() {
+ panel.remove(submitButton);
+ panel.remove(fu);
+ fu = new MyFileUpload();
+ fu.setName(paintableId + "_file");
+ fu.getElement().setPropertyBoolean("disabled", !enabled);
+ panel.add(fu);
+ panel.add(submitButton);
+ if (immediate) {
+ fu.sinkEvents(Event.ONCHANGE);
+ }
+ }
+
+ /**
+ * Called by JSNI (hooked via {@link #onloadstrategy})
+ */
+ private void onSubmitComplete() {
+ /* Needs to be run dereferred to avoid various browser issues. */
+ Scheduler.get().scheduleDeferred(new Command() {
+ @Override
+ public void execute() {
+ if (submitted) {
+ if (client != null) {
+ if (t != null) {
+ t.cancel();
+ }
+ VConsole.log("VUpload:Submit complete");
+ ((UploadConnector) ConnectorMap.get(client)
+ .getConnector(VUpload.this))
+ .getRpcProxy(UploadServerRpc.class)
+ .poll();
+ }
+
+ rebuildPanel();
+
+ submitted = false;
+ enableUpload();
+ if (!isAttached()) {
+ /*
+ * Upload is complete when upload is already abandoned.
+ */
+ cleanTargetFrame();
+ }
+ }
+ }
+ });
+ }
+
+ ScheduledCommand startUploadCmd = new ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ element.submit();
+ submitted = true;
+
+ disableUpload();
+
+ /*
+ * Visit server a moment after upload has started to see possible
+ * changes from UploadStarted event. Will be cleared on complete.
+ *
+ * Must get the id here as the upload can finish before the timer
+ * expires and in that case nextUploadId has been updated and is
+ * wrong.
+ */
+ final int thisUploadId = nextUploadId;
+ t = new Timer() {
+ @Override
+ public void run() {
+ // Only visit the server if the upload has not already
+ // finished
+ if (thisUploadId == nextUploadId) {
+ VConsole.log(
+ "Visiting server to see if upload started event changed UI.");
+ client.updateVariable(paintableId, "pollForStart",
+ thisUploadId, true);
+ }
+ }
+ };
+ t.schedule(800);
+ }
+
+ };
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public void submit() {
+ if (submitted || !enabled) {
+ VConsole.log("Submit cancelled (disabled or already submitted)");
+ return;
+ }
+ if (fu.getFilename().length() == 0) {
+ VConsole.log("Submitting empty selection (no file)");
+ }
+ // flush possibly pending variable changes, so they will be handled
+ // before upload
+ client.sendPendingVariableChanges();
+
+ // This is done as deferred because sendPendingVariableChanges is also
+ // deferred and we want to start the upload only after the changes have
+ // been sent to the server
+ Scheduler.get().scheduleDeferred(startUploadCmd);
+ }
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public void disableTitle(boolean disable) {
+ if (disable) {
+ // Disable title attribute for upload element.
+ if (BrowserInfo.get().isChrome()) {
+ // In Chrome title has to be set to " " to make it invisible
+ fu.setTitle(" ");
+ } else if (BrowserInfo.get().isFirefox()) {
+ // In FF title has to be set to empty string to make it
+ // invisible
+ // Method setTitle removes title attribute when it's an empty
+ // string, so setAttribute() should be used here
+ fu.getElement().setAttribute("title", "");
+ }
+ // For other browsers absent title doesn't show default tooltip for
+ // input element
+ } else {
+ fu.setTitle(null);
+ }
+ }
+
+ @Override
+ protected void onAttach() {
+ super.onAttach();
+ if (client != null) {
+ ensureTargetFrame();
+ }
+ }
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public void ensureTargetFrame() {
+ if (synthesizedFrame == null) {
+ // Attach a hidden IFrame to the form. This is the target iframe to
+ // which the form will be submitted. We have to create the iframe
+ // using innerHTML, because setting an iframe's 'name' property
+ // dynamically doesn't work on most browsers.
+ DivElement dummy = Document.get().createDivElement();
+ dummy.setInnerHTML("<iframe src=\"javascript:''\" name='"
+ + getFrameName()
+ + "' style='position:absolute;width:0;height:0;border:0'>");
+ synthesizedFrame = dummy.getFirstChildElement();
+ Document.get().getBody().appendChild(synthesizedFrame);
+ element.setTarget(getFrameName());
+ onloadstrategy.hookEvents(synthesizedFrame, this);
+ }
+ }
+
+ private String getFrameName() {
+ return paintableId + "_TGT_FRAME";
+ }
+
+ @Override
+ protected void onDetach() {
+ super.onDetach();
+ if (!submitted) {
+ cleanTargetFrame();
+ }
+ }
+
+ private void cleanTargetFrame() {
+ if (synthesizedFrame != null) {
+ Document.get().getBody().removeChild(synthesizedFrame);
+ onloadstrategy.unHookEvents(synthesizedFrame);
+ synthesizedFrame = null;
+ }
+ }
+
+}
diff --git a/compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadConnector.java b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadConnector.java
new file mode 100644
index 0000000000..eefbe60a1a
--- /dev/null
+++ b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadConnector.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2000-2016 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.v7.client.ui.upload;
+
+import com.google.gwt.event.dom.client.ChangeEvent;
+import com.google.gwt.event.dom.client.ChangeHandler;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.Paintable;
+import com.vaadin.client.UIDL;
+import com.vaadin.client.communication.StateChangeEvent;
+import com.vaadin.shared.EventId;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.v7.client.ui.AbstractLegacyComponentConnector;
+import com.vaadin.v7.client.ui.VUpload;
+import com.vaadin.v7.shared.ui.upload.UploadClientRpc;
+import com.vaadin.v7.shared.ui.upload.UploadServerRpc;
+import com.vaadin.v7.shared.ui.upload.UploadState;
+
+@Connect(com.vaadin.v7.ui.Upload.class)
+public class UploadConnector extends AbstractLegacyComponentConnector
+ implements Paintable {
+
+ public UploadConnector() {
+ registerRpc(UploadClientRpc.class, new UploadClientRpc() {
+ @Override
+ public void submitUpload() {
+ getWidget().submit();
+ }
+ });
+ }
+
+ @Override
+ protected void init() {
+ super.init();
+
+ getWidget().fu.addChangeHandler(new ChangeHandler() {
+ @Override
+ public void onChange(ChangeEvent event) {
+ if (hasEventListener(EventId.CHANGE)) {
+ getRpcProxy(UploadServerRpc.class)
+ .change(getWidget().fu.getFilename());
+ }
+ }
+ });
+ }
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ if (!isRealUpdate(uidl)) {
+ return;
+ }
+ if (uidl.hasAttribute("notStarted")) {
+ getWidget().t.schedule(400);
+ return;
+ }
+ getWidget().setImmediate(getState().immediate);
+ getWidget().client = client;
+ getWidget().paintableId = uidl.getId();
+ getWidget().nextUploadId = uidl.getIntAttribute("nextid");
+ final String action = client
+ .translateVaadinUri(uidl.getStringVariable("action"));
+ getWidget().element.setAction(action);
+ if (uidl.hasAttribute("buttoncaption")) {
+ getWidget().submitButton
+ .setText(uidl.getStringAttribute("buttoncaption"));
+ getWidget().submitButton.setVisible(true);
+ } else {
+ getWidget().submitButton.setVisible(false);
+ }
+ getWidget().fu.setName(getWidget().paintableId + "_file");
+
+ if (!isEnabled() || isReadOnly()) {
+ getWidget().disableUpload();
+ } else if (!uidl.getBooleanAttribute("state")) {
+ // Enable the button only if an upload is not in progress
+ getWidget().enableUpload();
+ getWidget().ensureTargetFrame();
+ }
+ }
+
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ super.onStateChanged(stateChangeEvent);
+
+ getWidget().disableTitle(hasTooltip());
+ }
+
+ @Override
+ public VUpload getWidget() {
+ return (VUpload) super.getWidget();
+ }
+
+ @Override
+ public UploadState getState() {
+ return (UploadState) super.getState();
+ }
+
+}
diff --git a/compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadIFrameOnloadStrategy.java b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadIFrameOnloadStrategy.java
new file mode 100644
index 0000000000..c01fce1b50
--- /dev/null
+++ b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadIFrameOnloadStrategy.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2000-2016 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.v7.client.ui.upload;
+
+import com.vaadin.v7.client.ui.VUpload;
+
+public class UploadIFrameOnloadStrategy {
+
+ public native void hookEvents(com.google.gwt.dom.client.Element iframe,
+ VUpload upload)
+ /*-{
+ iframe.onload = $entry(function() {
+ upload.@com.vaadin.client.ui.VUpload::onSubmitComplete()();
+ });
+ }-*/;
+
+ /**
+ * @param iframe
+ * the iframe whose onLoad event is to be cleaned
+ */
+ public native void unHookEvents(com.google.gwt.dom.client.Element iframe)
+ /*-{
+ iframe.onload = null;
+ }-*/;
+
+}
diff --git a/compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadIFrameOnloadStrategyIE.java b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadIFrameOnloadStrategyIE.java
new file mode 100644
index 0000000000..a40abfafdf
--- /dev/null
+++ b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadIFrameOnloadStrategyIE.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2016 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.v7.client.ui.upload;
+
+import com.google.gwt.dom.client.Element;
+import com.vaadin.v7.client.ui.VUpload;
+
+/**
+ * IE does not have onload, detect onload via readystatechange
+ *
+ */
+public class UploadIFrameOnloadStrategyIE extends UploadIFrameOnloadStrategy {
+ @Override
+ public native void hookEvents(Element iframe, VUpload upload)
+ /*-{
+ iframe.onreadystatechange = $entry(function() {
+ if (iframe.readyState == 'complete') {
+ upload.@com.vaadin.client.ui.VUpload::onSubmitComplete()();
+ }
+ });
+ }-*/;
+
+ @Override
+ public native void unHookEvents(Element iframe)
+ /*-{
+ iframe.onreadystatechange = null;
+ }-*/;
+
+}