Merge branch 'stable-2.16'
* stable-2.16:
Add user preferences panel to PolyGerrit UI
Add PolyGerrit-based screen for uploading images
Enable display of images in the comments in the new UI
Format code with GJF-1.7
Remove GWT UI
Change-Id: I90fb27bf89e673b3fd7321500c86ca4bbb63eaa6
diff --git a/BUILD b/BUILD
index 6adb380..7b71db2 100644
--- a/BUILD
+++ b/BUILD
@@ -3,7 +3,6 @@
gerrit_plugin(
name = "imagare",
srcs = glob(["src/main/java/**/*.java"]),
- gwt_module = "com.googlesource.gerrit.plugins.imagare.Imagare",
manifest_entries = [
"Gerrit-PluginName: imagare",
"Gerrit-Module: com.googlesource.gerrit.plugins.imagare.Module",
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/HttpModule.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/HttpModule.java
index d719e66..627cfd8 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/HttpModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/imagare/HttpModule.java
@@ -16,7 +16,6 @@
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.gerrit.extensions.webui.GwtPlugin;
import com.google.gerrit.extensions.webui.JavaScriptPlugin;
import com.google.gerrit.extensions.webui.WebUiPlugin;
import com.google.gerrit.httpd.plugins.HttpPluginModule;
@@ -40,7 +39,10 @@
serveRegex("^" + ImageServlet.PATH_PREFIX + "(.+)?$").with(ImageServlet.class);
}
- DynamicSet.bind(binder(), WebUiPlugin.class).toInstance(new GwtPlugin("imagare"));
+ // GWT only
DynamicSet.bind(binder(), WebUiPlugin.class).toInstance(new JavaScriptPlugin("imagare.js"));
+
+ // Polymer only
+ DynamicSet.bind(binder(), WebUiPlugin.class).toInstance(new JavaScriptPlugin("imagare.html"));
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/Imagare.gwt.xml b/src/main/java/com/googlesource/gerrit/plugins/imagare/Imagare.gwt.xml
deleted file mode 100644
index d363446..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/Imagare.gwt.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2014 The Android Open Source Project
-
- 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.
--->
-<module rename-to="imagare">
- <!-- Inherit the core Web Toolkit stuff. -->
- <inherits name="com.google.gwt.user.User"/>
- <!-- Other module inherits -->
- <inherits name="com.google.gerrit.Plugin"/>
- <inherits name="com.google.gwt.http.HTTP"/>
- <inherits name='com.google.gwtexpui.clippy.Clippy'/>
- <!-- Specify the app entry point class. -->
- <entry-point class="com.googlesource.gerrit.plugins.imagare.client.ImagarePlugin"/>
- <stylesheet src="imagare.css"/>
-</module>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfigInfo.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfigInfo.java
deleted file mode 100644
index 65d9b96..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfigInfo.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-import com.google.gwt.core.client.JavaScriptObject;
-
-public class ConfigInfo extends JavaScriptObject {
- final native String getDefaultProject() /*-{ return this.default_project }-*/;
-
- final LinkDecoration getLinkDecoration() {
- if (link_decoration() == null) {
- return LinkDecoration.NONE;
- }
- return LinkDecoration.valueOf(link_decoration());
- }
-
- private final native String link_decoration() /*-{ return this.link_decoration; }-*/;
-
- final native boolean stage() /*-{ return this.stage ? true : false; }-*/;
-
- final native boolean
- enableImageServer() /*-{ return this.enable_image_server ? true : false; }-*/;
-
- final native void setDefaultProject(String p) /*-{ this.default_project = p; }-*/;
-
- final native void setLinkDecoration(String d) /*-{ this.link_decoration = d; }-*/;
-
- final native void setStage(boolean s) /*-{ this.stage = s; }-*/;
-
- static ConfigInfo create() {
- ConfigInfo g = (ConfigInfo) createObject();
- return g;
- }
-
- protected ConfigInfo() {}
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfirmationCallback.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfirmationCallback.java
deleted file mode 100644
index 209d14f..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfirmationCallback.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-/**
- * Interface that a caller must implement to react on the result of a {@link ConfirmationDialog}.
- */
-public abstract class ConfirmationCallback {
-
- /**
- * Called when the {@link ConfirmationDialog} is finished with OK. To be overwritten by
- * subclasses.
- */
- public abstract void onOk();
-
- /**
- * Called when the {@link ConfirmationDialog} is finished with Cancel. To be overwritten by
- * subclasses.
- */
- public void onCancel() {}
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfirmationDialog.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfirmationDialog.java
deleted file mode 100644
index 062f8df..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfirmationDialog.java
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.google.gwtexpui.safehtml.client.SafeHtml;
-import com.google.gwtexpui.user.client.AutoCenterDialogBox;
-
-public class ConfirmationDialog extends AutoCenterDialogBox {
-
- private Button cancelButton;
-
- public ConfirmationDialog(
- final String dialogTitle, final SafeHtml message, final ConfirmationCallback callback) {
- super(/* auto hide */ false, /* modal */ true);
- setGlassEnabled(true);
- setText(dialogTitle);
-
- final FlowPanel buttons = new FlowPanel();
-
- final Button okButton = new Button();
- okButton.setText("OK");
- okButton.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- hide();
- callback.onOk();
- }
- });
- buttons.add(okButton);
-
- cancelButton = new Button();
- cancelButton.getElement().getStyle().setProperty("marginLeft", "300px");
- cancelButton.setText("Cancel");
- cancelButton.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- hide();
- callback.onCancel();
- }
- });
- buttons.add(cancelButton);
-
- final FlowPanel center = new FlowPanel();
- final Widget msgWidget = message.toBlockWidget();
- center.add(msgWidget);
- center.add(buttons);
- add(center);
-
- msgWidget.setWidth("400px");
-
- setWidget(center);
- }
-
- @Override
- public void center() {
- super.center();
- cancelButton.setFocus(true);
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImagareAdminScreen.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImagareAdminScreen.java
deleted file mode 100644
index 78d6945..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImagareAdminScreen.java
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-import com.google.gerrit.plugin.client.Plugin;
-import com.google.gerrit.plugin.client.rpc.RestApi;
-import com.google.gerrit.plugin.client.screen.Screen;
-
-public class ImagareAdminScreen extends ImagareConfigScreen {
-
- static class Factory implements Screen.EntryPoint {
- private final boolean enableImageServer;
-
- Factory(boolean enableImageServer) {
- this.enableImageServer = enableImageServer;
- }
-
- @Override
- public void onLoad(Screen screen) {
- screen.setPageTitle(Plugin.get().getName() + "Admin");
- screen.show(new ImagareAdminScreen(enableImageServer));
- }
- }
-
- ImagareAdminScreen(boolean enableImageServer) {
- super(
- enableImageServer,
- new RestApi("config").id("server").view(Plugin.get().getPluginName(), "config"));
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImagareConfigScreen.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImagareConfigScreen.java
deleted file mode 100644
index cc261c9..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImagareConfigScreen.java
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-import com.google.gerrit.plugin.client.rpc.RestApi;
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.CheckBox;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.Image;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.ListBox;
-import com.google.gwt.user.client.ui.TextBox;
-import com.google.gwt.user.client.ui.VerticalPanel;
-
-public abstract class ImagareConfigScreen extends VerticalPanel {
- protected final boolean enableImageServer;
- private final RestApi restApi;
-
- private TextBox projectBox;
- private ListBox linkDecorationBox;
- private CheckBox stageBox;
- private Button saveButton;
-
- protected ImagareConfigScreen(boolean enableImageServer, RestApi restApi) {
- this.enableImageServer = enableImageServer;
- this.restApi = restApi;
- setStyleName("imagare-config-screen");
- restApi.get(
- new AsyncCallback<ConfigInfo>() {
- @Override
- public void onSuccess(ConfigInfo info) {
- display(info);
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
-
- protected void display(ConfigInfo info) {
- HorizontalPanel p = new HorizontalPanel();
- p.setStyleName("imagare-label-panel");
- p.add(new Label("Link Decoration"));
- Image linkDecorationInfo = new Image(ImagarePlugin.RESOURCES.info());
- linkDecorationInfo.setTitle(
- "Decoration for image links in the Gerrit WebUI."
- + " 'NONE': no decoration, 'TOOLTIP': the image is shown as tooltip on"
- + " mouse over an image link, 'INLINE': the image is inlined instead of"
- + " the URL.");
- p.add(linkDecorationInfo);
- p.add(new Label(":"));
- linkDecorationBox = new ListBox();
- int i = 0;
- for (LinkDecoration v : LinkDecoration.values()) {
- linkDecorationBox.addItem(v.name());
- if (v.equals(info.getLinkDecoration())) {
- linkDecorationBox.setSelectedIndex(i);
- }
- i++;
- }
- p.add(linkDecorationBox);
- add(p);
-
- if (enableImageServer) {
- p = new HorizontalPanel();
- p.setStyleName("imagare-label-panel");
- p.add(new Label("Project"));
- Image projectInfo = new Image(ImagarePlugin.RESOURCES.info());
- projectInfo.setTitle("The default project for the image upload.");
- p.add(projectInfo);
- p.add(new Label(":"));
- projectBox = new TextBox();
- projectBox.setValue(info.getDefaultProject());
- p.add(projectBox);
- add(p);
-
- p = new HorizontalPanel();
- p.setStyleName("imagare-label-panel");
- stageBox = new CheckBox("Stage images before upload");
- stageBox.setValue(info.stage());
- p.add(stageBox);
- Image stageInfo = new Image(ImagarePlugin.RESOURCES.info());
- stageInfo.setTitle(
- "Images are not uploaded immediately but put into a "
- + "staging area. The upload must be triggered explicitely.");
- p.add(stageInfo);
- add(p);
- }
-
- HorizontalPanel buttons = new HorizontalPanel();
- add(buttons);
-
- saveButton = new Button("Save");
- saveButton.setStyleName("imagare-save-button");
- saveButton.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(final ClickEvent event) {
- doSave();
- }
- });
- buttons.add(saveButton);
- saveButton.setEnabled(false);
- OnEditEnabler onEditEnabler = new OnEditEnabler(saveButton, linkDecorationBox);
- if (enableImageServer) {
- onEditEnabler.listenTo(projectBox);
- onEditEnabler.listenTo(stageBox);
- }
-
- projectBox.setFocus(true);
- saveButton.setEnabled(false);
- }
-
- private void doSave() {
- ConfigInfo in = ConfigInfo.create();
- in.setLinkDecoration(linkDecorationBox.getValue(linkDecorationBox.getSelectedIndex()));
- if (enableImageServer) {
- in.setDefaultProject(projectBox.getValue());
- in.setStage(stageBox.getValue());
- }
- restApi.put(
- in,
- new AsyncCallback<JavaScriptObject>() {
- @Override
- public void onSuccess(JavaScriptObject result) {
- saveButton.setEnabled(false);
- onSave();
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
-
- protected void onSave() {}
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImagarePlugin.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImagarePlugin.java
deleted file mode 100644
index 086bd13..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImagarePlugin.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-import com.google.gerrit.plugin.client.Plugin;
-import com.google.gerrit.plugin.client.PluginEntryPoint;
-import com.google.gerrit.plugin.client.rpc.RestApi;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-
-public class ImagarePlugin extends PluginEntryPoint {
- public static final Resources RESOURCES = GWT.create(Resources.class);
-
- @Override
- public void onPluginLoad() {
- new RestApi("config")
- .id("server")
- .view(Plugin.get().getPluginName(), "config")
- .get(
- new AsyncCallback<ConfigInfo>() {
- @Override
- public void onSuccess(ConfigInfo info) {
- if (info.enableImageServer()) {
- Plugin.get().screen("upload", new ImageUploadScreen.Factory());
- }
-
- Plugin.get()
- .screen("settings", new ImagareAdminScreen.Factory(info.enableImageServer()));
- Plugin.get()
- .settingsScreen(
- "preferences",
- Plugin.get().getName() + " Preferences",
- new ImagarePreferenceScreen.Factory(info.enableImageServer()));
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImagarePreferenceScreen.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImagarePreferenceScreen.java
deleted file mode 100644
index a9cd182..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImagarePreferenceScreen.java
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-import com.google.gerrit.plugin.client.Plugin;
-import com.google.gerrit.plugin.client.rpc.RestApi;
-import com.google.gerrit.plugin.client.screen.Screen;
-import com.google.gwt.user.client.Cookies;
-import com.google.gwt.user.client.ui.Anchor;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.ImageResourceRenderer;
-
-public class ImagarePreferenceScreen extends ImagareConfigScreen {
-
- static class Factory implements Screen.EntryPoint {
- private final boolean enableImageServer;
-
- Factory(boolean enableImageServer) {
- this.enableImageServer = enableImageServer;
- }
-
- @Override
- public void onLoad(Screen screen) {
- screen.setPageTitle(Plugin.get().getName() + " Preferences");
- screen.show(new ImagarePreferenceScreen(enableImageServer));
- }
- }
-
- ImagarePreferenceScreen(boolean enableImageServer) {
- super(
- enableImageServer,
- new RestApi("accounts").id("self").view(Plugin.get().getPluginName(), "preference"));
- }
-
- @Override
- protected void display(ConfigInfo info) {
- if (enableImageServer) {
- HorizontalPanel p = new HorizontalPanel();
- p.setStyleName("imagare-menu-panel");
- Anchor uploadAnchor =
- new Anchor(
- new ImageResourceRenderer().render(ImagarePlugin.RESOURCES.image()),
- "#/x/" + Plugin.get().getPluginName() + "/upload");
- uploadAnchor.setTitle("Upload Image");
- p.add(uploadAnchor);
- add(p);
- }
-
- super.display(info);
- }
-
- @Override
- protected void onSave() {
- super.onSave();
- Cookies.removeCookie(Plugin.get().getPluginName() + "~prefs");
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImageUploadScreen.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImageUploadScreen.java
deleted file mode 100644
index a146a2e..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImageUploadScreen.java
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-import com.google.gerrit.plugin.client.Plugin;
-import com.google.gerrit.plugin.client.rpc.RestApi;
-import com.google.gerrit.plugin.client.screen.Screen;
-import com.google.gwt.http.client.URL;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.Anchor;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.Image;
-import com.google.gwt.user.client.ui.ImageResourceRenderer;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.TextBox;
-import com.google.gwt.user.client.ui.VerticalPanel;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class ImageUploadScreen extends VerticalPanel {
-
- static class Factory implements Screen.EntryPoint {
- @Override
- public void onLoad(Screen screen) {
- screen.setPageTitle("Image Upload");
- screen.show(new ImageUploadScreen());
- }
- }
-
- static TextBox projectBox;
- static UploadStagePanel uploadStagePanel;
- static UploadedImagesPanel uploadedPanel;
-
- private final UploadByDropOrPastePanel uploadPanel;
-
- ImageUploadScreen() {
- setStyleName("imagare-image-upload-screen");
-
- HorizontalPanel p = new HorizontalPanel();
- p.setStyleName("imagare-menu-panel");
- Anchor prefsAnchor =
- new Anchor(
- new ImageResourceRenderer().render(ImagarePlugin.RESOURCES.gear()),
- "#/settings/x/" + Plugin.get().getPluginName() + "/preferences");
- prefsAnchor.setTitle("Edit Preferences");
- p.add(prefsAnchor);
- add(p);
-
- p = new HorizontalPanel();
- p.setStyleName("imagare-label-panel");
- p.add(new Label("Project"));
- Image projectInfo = new Image(ImagarePlugin.RESOURCES.info());
- projectInfo.setTitle("The project to which the images are uploaded.");
- p.add(projectInfo);
- p.add(new Label(":"));
- projectBox = new TextBox();
- p.add(projectBox);
- add(p);
-
- add(new UploadByFileSelection());
- uploadPanel = new UploadByDropOrPastePanel();
- add(uploadPanel);
- uploadStagePanel = new UploadStagePanel();
- add(uploadStagePanel);
- uploadedPanel = new UploadedImagesPanel();
- add(uploadedPanel);
-
- new RestApi("accounts")
- .id("self")
- .view(Plugin.get().getPluginName(), "preference")
- .get(
- new AsyncCallback<ConfigInfo>() {
- @Override
- public void onSuccess(ConfigInfo info) {
- ImageUploader.setStage(info.stage());
- String project = getParameter("project");
- if (project != null) {
- projectBox.setValue(project);
- } else {
- projectBox.setValue(info.getDefaultProject());
- }
- uploadPanel.focus();
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
-
- private static String getParameter(String name) {
- List<String> values = getParameters().get(name);
- if (values == null) {
- return null;
- }
- return values.get(values.size() - 1);
- }
-
- private static Map<String, List<String>> getParameters() {
- Map<String, List<String>> parameter = new HashMap<>();
-
- if (!Window.Location.getHash().contains("?")) {
- return parameter;
- }
-
- String queryString =
- Window.Location.getHash().substring(Window.Location.getHash().indexOf('?') + 1);
- for (String kvPair : queryString.split("&")) {
- String[] kv = kvPair.split("=", 2);
- if (kv[0].length() == 0) {
- continue;
- }
-
- List<String> values = parameter.get(kv[0]);
- if (values == null) {
- values = new ArrayList<>();
- parameter.put(kv[0], values);
- }
- values.add(kv.length > 1 ? URL.decodeQueryString(kv[1]) : "");
- }
-
- return parameter;
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImageUploader.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImageUploader.java
deleted file mode 100644
index 057f615..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ImageUploader.java
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-import com.google.gerrit.plugin.client.Plugin;
-import com.google.gerrit.plugin.client.rpc.RestApi;
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-
-public class ImageUploader {
- private static boolean stage;
-
- public static void setStage(boolean s) {
- stage = s;
- }
-
- public static final void stageImage(String imageData) {
- stageImage(imageData, null);
- }
-
- public static final void stageImage(String imageData, String fileName) {
- stageImage(ImageUploadScreen.projectBox.getValue(), imageData, fileName);
- }
-
- public static final void stageImage(String project, String imageData, String fileName) {
- if (stage) {
- ImageUploadScreen.uploadStagePanel.add(project, imageData, fileName);
- } else {
- uploadImage(project, imageData, fileName);
- }
- }
-
- public static final void uploadImage(String imageData) {
- uploadImage(imageData, null);
- }
-
- public static final void uploadImage(String imageData, String fileName) {
- uploadImage(ImageUploadScreen.projectBox.getValue(), imageData, fileName);
- }
-
- public static final void uploadImage(String project, String imageData, String fileName) {
- ImageInput in = ImageInput.create();
- in.image_data(imageData);
- in.file_name(fileName);
-
- new RestApi("projects")
- .id(project)
- .view(Plugin.get().getPluginName(), "images")
- .post(
- in,
- new AsyncCallback<ImageInfo>() {
-
- @Override
- public void onSuccess(ImageInfo result) {
- ImageUploadScreen.uploadedPanel.add(result.url());
- }
-
- @Override
- public void onFailure(Throwable caught) {}
- });
- }
-
- private static class ImageInput extends JavaScriptObject {
- final native void image_data(String d) /*-{ this.image_data = d; }-*/;
-
- final native void file_name(String n) /*-{ this.file_name = n; }-*/;
-
- static ImageInput create() {
- return (ImageInput) createObject();
- }
-
- protected ImageInput() {}
- }
-
- private static class ImageInfo extends JavaScriptObject {
- final native String url() /*-{ return this.url }-*/;
-
- protected ImageInfo() {}
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/LinkDecoration.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/LinkDecoration.java
deleted file mode 100644
index b44b075..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/LinkDecoration.java
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-public enum LinkDecoration {
- NONE,
- TOOLTIP,
- INLINE
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/OnEditEnabler.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/OnEditEnabler.java
deleted file mode 100644
index 7be0614..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/OnEditEnabler.java
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-import com.google.gwt.core.client.Scheduler;
-import com.google.gwt.core.client.Scheduler.ScheduledCommand;
-import com.google.gwt.event.dom.client.ChangeEvent;
-import com.google.gwt.event.dom.client.ChangeHandler;
-import com.google.gwt.event.dom.client.FocusEvent;
-import com.google.gwt.event.dom.client.FocusHandler;
-import com.google.gwt.event.dom.client.KeyDownEvent;
-import com.google.gwt.event.dom.client.KeyDownHandler;
-import com.google.gwt.event.dom.client.KeyPressEvent;
-import com.google.gwt.event.dom.client.KeyPressHandler;
-import com.google.gwt.event.dom.client.MouseUpEvent;
-import com.google.gwt.event.dom.client.MouseUpHandler;
-import com.google.gwt.event.logical.shared.ValueChangeEvent;
-import com.google.gwt.event.logical.shared.ValueChangeHandler;
-import com.google.gwt.event.shared.GwtEvent;
-import com.google.gwt.user.client.ui.CheckBox;
-import com.google.gwt.user.client.ui.FocusWidget;
-import com.google.gwt.user.client.ui.ListBox;
-import com.google.gwt.user.client.ui.TextBoxBase;
-import com.google.gwt.user.client.ui.ValueBoxBase;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Enables a FocusWidget (e.g. a Button) if an edit is detected from any registered input widget.
- */
-public class OnEditEnabler
- implements KeyPressHandler,
- KeyDownHandler,
- MouseUpHandler,
- ChangeHandler,
- ValueChangeHandler<Object> {
-
- private final FocusWidget widget;
- private Map<TextBoxBase, String> strings = new HashMap<>();
- private String originalValue;
-
- // The first parameter to the constructors must be the FocusWidget to enable,
- // subsequent parameters are widgets to listenTo.
-
- public OnEditEnabler(final FocusWidget w, final TextBoxBase tb) {
- this(w);
- originalValue = tb.getValue().trim();
- listenTo(tb);
- }
-
- public OnEditEnabler(final FocusWidget w, final ListBox lb) {
- this(w);
- listenTo(lb);
- }
-
- public OnEditEnabler(final FocusWidget w, final CheckBox cb) {
- this(w);
- listenTo(cb);
- }
-
- public OnEditEnabler(final FocusWidget w) {
- widget = w;
- }
-
- // Register input widgets to be listened to
-
- public void listenTo(final TextBoxBase tb) {
- strings.put(tb, tb.getText().trim());
- tb.addKeyPressHandler(this);
-
- // Is there another way to capture middle button X11 pastes in browsers
- // which do not yet support ONPASTE events (Firefox)?
- tb.addMouseUpHandler(this);
-
- // Resetting the "original text" on focus ensures that we are
- // up to date with non-user updates of the text (calls to
- // setText()...) and also up to date with user changes which
- // occured after enabling "widget".
- tb.addFocusHandler(
- new FocusHandler() {
- @Override
- public void onFocus(FocusEvent event) {
- strings.put(tb, tb.getText().trim());
- }
- });
-
- // CTRL-V Pastes in Chrome seem only detectable via BrowserEvents or
- // KeyDownEvents, the latter is better.
- tb.addKeyDownHandler(this);
- }
-
- public void listenTo(final ListBox lb) {
- lb.addChangeHandler(this);
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- public void listenTo(final CheckBox cb) {
- cb.addValueChangeHandler((ValueChangeHandler) this);
- }
-
- // Handlers
-
- @Override
- public void onKeyPress(final KeyPressEvent e) {
- on(e);
- }
-
- @Override
- public void onKeyDown(final KeyDownEvent e) {
- on(e);
- }
-
- @Override
- public void onMouseUp(final MouseUpEvent e) {
- on(e);
- }
-
- @Override
- public void onChange(final ChangeEvent e) {
- on(e);
- }
-
- @SuppressWarnings("rawtypes")
- @Override
- public void onValueChange(final ValueChangeEvent e) {
- on(e);
- }
-
- private void on(final GwtEvent<?> e) {
- if (widget.isEnabled()
- || !(e.getSource() instanceof FocusWidget)
- || !((FocusWidget) e.getSource()).isEnabled()) {
- if (e.getSource() instanceof ValueBoxBase) {
- final TextBoxBase box = ((TextBoxBase) e.getSource());
- Scheduler.get()
- .scheduleDeferred(
- new ScheduledCommand() {
- @Override
- public void execute() {
- if (box.getValue().trim().equals(originalValue)) {
- widget.setEnabled(false);
- }
- }
- });
- }
- return;
- }
-
- if (e.getSource() instanceof TextBoxBase) {
- onTextBoxBase((TextBoxBase) e.getSource());
- } else {
- // For many widgets, we can assume that a change is an edit. If
- // a widget does not work that way, it should be special cased
- // above.
- widget.setEnabled(true);
- }
- }
-
- private void onTextBoxBase(final TextBoxBase tb) {
- // The text appears to not get updated until the handlers complete.
- Scheduler.get()
- .scheduleDeferred(
- new ScheduledCommand() {
- @Override
- public void execute() {
- String orig = strings.get(tb);
- if (orig == null) {
- orig = "";
- }
- if (!orig.equals(tb.getText().trim())) {
- widget.setEnabled(true);
- }
- }
- });
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/Resources.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/Resources.java
deleted file mode 100644
index 7e85e6e..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/Resources.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-import com.google.gwt.resources.client.ImageResource;
-
-public interface Resources extends com.google.gerrit.client.Resources {
-
- @Source("delete.png")
- public ImageResource delete();
-
- @Source("fullscreen.png")
- public ImageResource fullScreen();
-
- @Source("image.png")
- public ImageResource image();
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadByDropOrPastePanel.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadByDropOrPastePanel.java
deleted file mode 100644
index c4ed0d5..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadByDropOrPastePanel.java
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.VerticalPanel;
-
-public class UploadByDropOrPastePanel extends VerticalPanel {
-
- UploadByDropOrPastePanel() {
- init0();
-
- setStyleName("imagare-image-upload-panel");
- getElement().setAttribute("contenteditable", "true");
- getElement().setAttribute("onpaste", "imagarePasteHandler(this, event)");
- getElement().setAttribute("ondrop", "imagareDropHandler(this, event)");
- getElement().setAttribute("onkeypress", "imagarePreventKeyPress(event)");
-
- add(new Label("drag and drop image here"));
- add(new Label("or"));
- add(new Label("paste image from clipboard with " + (isMac() ? "Cmd+V" : "Ctrl+V")));
- }
-
- private static native boolean isMac() /*-{
- return navigator.platform.toUpperCase().indexOf('MAC') >= 0;
- }-*/;
-
- private static native void init0() /*-{
- $wnd.imagarePreventKeyPress = function preventKeys(event) {
- event = event || window.event;
- var ctrlDown = event.ctrlKey || event.metaKey;
- if (!ctrlDown) {
- event.preventDefault();
- }
- }
-
- var imagareSavedContent;
-
- $wnd.imagarePasteHandler = function handlePaste(elem, e) {
- if (!imagareSavedContent) {
- imagareSavedContent = elem.innerHTML;
- }
-
- var clipboardData = e.clipboardData || e.originalEvent.clipboardData;
- var items = clipboardData.items;
-
- if (JSON.stringify(items)) {
- // Chrome
-
- var blob;
- for (var i = 0; i < items.length; i++) {
- if (items[i].type.indexOf("image") === 0) {
- blob = items[i].getAsFile();
- }
- }
-
- if (blob) {
- var reader = new FileReader();
- reader.onload = function(e) {
- @com.googlesource.gerrit.plugins.imagare.client.ImageUploader::stageImage(Ljava/lang/String;)(e.target.result);
- };
- reader.readAsDataURL(blob);
- } else {
- e.preventDefault();
- $wnd.Gerrit.showError('no image data');
- }
- } else if (e && e.clipboardData && e.clipboardData.getData) {
- // Webkit
-
- if ((/text\/html/.test(e.clipboardData.types[0]))
- || (/text\/plain/.test(e.clipboardData.types[0]))) {
- elem.innerHTML = '<div>' + e.clipboardData.getData(e.clipboardData.types[0]) + '</div>';
- } else {
- elem.innerHTML = "";
- }
-
- waitOnPaste(10, elem);
- } else {
- // other browser
-
- elem.innerHTML = "";
- waitOnPaste(10, elem);
- }
- }
-
- function waitOnPaste(max, elem) {
- if (elem.childNodes && elem.childNodes.length > 0) {
- stageImage(elem);
- } else if (max > 0) {
- that = {
- m: max - 1,
- e: elem,
- }
- that.callself = function () {
- waitOnPaste(that.m, that.e)
- }
- setTimeout(that.callself, 20);
- }
- }
-
- function stageImage(elem) {
- var imageData = elem.childNodes[0].getAttribute("src");
- elem.innerHTML = imagareSavedContent;
- @com.googlesource.gerrit.plugins.imagare.client.ImageUploader::stageImage(Ljava/lang/String;)(imageData);
- }
-
- $wnd.imagareDropHandler = function handleDrop(elem, event) {
- if (window.chrome) {
- event.preventDefault();
- }
- if (!imagareSavedContent) {
- imagareSavedContent = elem.innerHTML;
- }
- for(var i = 0; i < event.dataTransfer.files.length; i++) {
- var f = event.dataTransfer.files[i];
- if (f) {
- if (!f.type.match('image/.*')) {
- $wnd.Gerrit.showError('no image file: ' + f.name);
- }
-
- var r = new FileReader();
- r.file = f;
- r.onload = function(e) {
- elem.innerHTML = imagareSavedContent;
- @com.googlesource.gerrit.plugins.imagare.client.ImageUploader::stageImage(Ljava/lang/String;Ljava/lang/String;)(e.target.result, this.file.name);
- }
- r.readAsDataURL(f);
- } else {
- $wnd.Gerrit.showError('Failed to load file: ' + f.name);
- }
- }
- }
- }-*/;
-
- public void focus() {
- focus(getElement());
- }
-
- private static native void focus(Element elem) /*-{
- var range = document.createRange();
- var sel = window.getSelection();
- range.selectNode(elem);
- range.collapse(true);
- sel.removeAllRanges();
- sel.addRange(range);
- elem.focus();
- }-*/;
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadByFileSelection.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadByFileSelection.java
deleted file mode 100644
index 516644b..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadByFileSelection.java
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-import com.google.gwt.user.client.ui.FileUpload;
-import com.google.gwt.user.client.ui.FormPanel;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-
-public class UploadByFileSelection extends HorizontalPanel {
- UploadByFileSelection() {
- init0();
-
- FormPanel form = new FormPanel();
- FileUpload upload = new FileUpload();
- upload.setName("Select Image");
- upload.getElement().setAttribute("multiple", "multiple");
- upload.getElement().setAttribute("onChange", "imagareSubmit(event)");
- form.add(upload);
-
- add(form);
- }
-
- private static native void init0() /*-{
- $wnd.imagareSubmit = function submit(event) {
- for(var i = 0; i < event.target.files.length; i++) {
- var f = event.target.files[i];
- if (f) {
- if (!f.type.match('image/.*')) {
- $wnd.Gerrit.showError('no image file: ' + f.name);
- }
-
- var r = new FileReader();
- r.file = f;
- r.onload = function(e) {
- @com.googlesource.gerrit.plugins.imagare.client.ImageUploader::stageImage(Ljava/lang/String;Ljava/lang/String;)(e.target.result, this.file.name);
- }
- r.readAsDataURL(f);
- } else {
- $wnd.Gerrit.showError('Failed to load file: ' + f.name);
- }
- }
- }
- }-*/;
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadStagePanel.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadStagePanel.java
deleted file mode 100644
index 4ff11b0..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadStagePanel.java
+++ /dev/null
@@ -1,328 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-import static com.google.gwt.event.dom.client.KeyCodes.KEY_ENTER;
-import static com.google.gwt.event.dom.client.KeyCodes.KEY_ESCAPE;
-
-import com.google.gwt.event.dom.client.BlurEvent;
-import com.google.gwt.event.dom.client.BlurHandler;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.dom.client.DoubleClickEvent;
-import com.google.gwt.event.dom.client.DoubleClickHandler;
-import com.google.gwt.event.dom.client.KeyDownEvent;
-import com.google.gwt.event.dom.client.KeyDownHandler;
-import com.google.gwt.event.dom.client.MouseOutEvent;
-import com.google.gwt.event.dom.client.MouseOutHandler;
-import com.google.gwt.event.dom.client.MouseOverEvent;
-import com.google.gwt.event.dom.client.MouseOverHandler;
-import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.Image;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.PopupPanel;
-import com.google.gwt.user.client.ui.TextBox;
-import com.google.gwt.user.client.ui.VerticalPanel;
-
-public class UploadStagePanel extends VerticalPanel {
-
- private Label uploadedImagesLabel;
- private FlowPanel stagedImagesPanel;
- private PopupPanel popup;
-
- UploadStagePanel() {
- setStyleName("imagare-upload-stage-panel");
- setVisible(false);
-
- uploadedImagesLabel = new Label("Staged Images:");
- uploadedImagesLabel.setStyleName("imagare-staged-images-label");
- add(uploadedImagesLabel);
-
- stagedImagesPanel = new FlowPanel();
- stagedImagesPanel.setStyleName("imagare-staged-images-panel");
- add(stagedImagesPanel);
-
- HorizontalPanel buttons = new HorizontalPanel();
- add(buttons);
-
- Button uploadButton = new Button("Upload");
- uploadButton.setStyleName("imagare-upload-button");
- uploadButton.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(final ClickEvent event) {
- doUpload();
- }
- });
- buttons.add(uploadButton);
-
- Button cleanButton = new Button("Clean");
- cleanButton.setStyleName("imagare-clean-button");
- cleanButton.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(final ClickEvent event) {
- stagedImagesPanel.clear();
- setVisible(false);
- }
- });
- buttons.add(cleanButton);
-
- popup = new PopupPanel();
- popup.setVisible(false);
- }
-
- void add(String project, String dataUrl, String fileName) {
- setVisible(true);
- if (!isStaged(project, dataUrl, fileName)) {
- stagedImagesPanel.insert(new ImagePreview(project, dataUrl, fileName), 0);
- }
- }
-
- boolean isStaged(String project, String dataUrl, String fileName) {
- for (int i = 0; i < stagedImagesPanel.getWidgetCount(); i++) {
- ImagePreview ip = (ImagePreview) stagedImagesPanel.getWidget(i);
- if (project.equals(ip.project)
- && dataUrl.endsWith(ip.dataUrl)
- && (fileName != null ? fileName.equals(ip.fileName) : ip.fileName == null)) {
- return true;
- }
- }
- return false;
- }
-
- private void doUpload() {
- for (int i = 0; i < stagedImagesPanel.getWidgetCount(); i++) {
- ImagePreview ip = (ImagePreview) stagedImagesPanel.getWidget(i);
- ImageUploader.uploadImage(ip.project, ip.dataUrl, ip.fileName);
- }
- stagedImagesPanel.clear();
- setVisible(false);
- }
-
- private class ImagePreview extends VerticalPanel {
- final String project;
- final String dataUrl;
- String fileName;
-
- private final Image img;
- private final Image deleteIcon;
- private Timer deleteIconHideTimer;
-
- ImagePreview(String project, final String dataUrl, String fileName) {
- this.project = project;
- this.dataUrl = dataUrl;
- this.fileName = fileName;
-
- setStyleName("imagare-stage-image-preview-panel");
-
- addFileName();
-
- img = new Image(dataUrl);
- img.setStyleName("imagare-stage-image-preview");
- add(img);
-
- deleteIcon = new Image(ImagarePlugin.RESOURCES.delete());
- deleteIcon.setStyleName("imagare-delete-icon");
- deleteIcon.setTitle("Delete Image");
- deleteIcon.setVisible(false);
- add(deleteIcon);
-
- img.addMouseOverHandler(
- new MouseOverHandler() {
- @Override
- public void onMouseOver(MouseOverEvent event) {
- if (!popup.isVisible()) {
- Image previewImg = new Image(dataUrl);
- previewImg.setStyleName("imagare-image-popup");
- previewImg
- .getElement()
- .setAttribute(
- "style",
- previewImg.getElement().getAttribute("style")
- + "position: absolute; top: "
- + (img.getAbsoluteTop() + img.getHeight() + 20)
- + "px; "
- + "left: "
- + img.getAbsoluteLeft()
- + "px;");
- popup.add(previewImg);
-
- popup.show();
- popup.setVisible(true);
- }
-
- cancelHideDeleteIcon();
- deleteIcon
- .getElement()
- .setAttribute(
- "style",
- deleteIcon.getElement().getAttribute("style")
- + "position: absolute; top: "
- + img.getAbsoluteTop()
- + "px; "
- + "left: "
- + img.getAbsoluteLeft()
- + "px;");
- deleteIcon.setVisible(true);
- }
- });
- img.addMouseOutHandler(
- new MouseOutHandler() {
- @Override
- public void onMouseOut(MouseOutEvent event) {
- popup.setVisible(false);
- popup.clear();
- hideDeleteIcon();
- }
- });
-
- deleteIcon.addMouseOverHandler(
- new MouseOverHandler() {
- @Override
- public void onMouseOver(MouseOverEvent event) {
- cancelHideDeleteIcon();
- }
- });
-
- deleteIcon.addMouseOutHandler(
- new MouseOutHandler() {
- @Override
- public void onMouseOut(MouseOutEvent event) {
- hideDeleteIcon();
- }
- });
-
- deleteIcon.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- stagedImagesPanel.remove(ImagePreview.this);
- UploadStagePanel.this.setVisible(stagedImagesPanel.getWidgetCount() != 0);
- popup.setVisible(false);
- popup.clear();
- }
- });
-
- Label projectLabel = new Label("Project: " + project);
- projectLabel.setStyleName("imagare-stage-label");
- add(projectLabel);
- }
-
- private void hideDeleteIcon() {
- deleteIconHideTimer =
- new Timer() {
- @Override
- public void run() {
- deleteIcon.setVisible(false);
- }
- };
- deleteIconHideTimer.schedule(20);
- }
-
- private void cancelHideDeleteIcon() {
- if (deleteIconHideTimer != null) {
- deleteIconHideTimer.cancel();
- deleteIconHideTimer = null;
- }
- }
-
- private void addFileName() {
- final Label fileNameLabel = new Label(fileName != null ? fileName : "img.png");
- fileNameLabel.setStyleName("imagare-stage-image-title");
- add(fileNameLabel);
-
- fileNameLabel.addDoubleClickHandler(
- new DoubleClickHandler() {
- @Override
- public void onDoubleClick(DoubleClickEvent event) {
- fileNameLabel.setVisible(false);
- FileNameEditPanel fileNameEditPanel =
- new FileNameEditPanel(ImagePreview.this, fileNameLabel);
- insert(fileNameEditPanel, getWidgetIndex(fileNameLabel));
- fileNameEditPanel.focusAndSelectAll();
- }
- });
- }
-
- private class FileNameEditPanel extends HorizontalPanel {
- private final ImagePreview imagePreview;
- private final Label fileNameLabel;
- private final TextBox fileNameBox;
- private final String name;
- private final String extension;
-
- FileNameEditPanel(ImagePreview imagePreview, Label fileNameLabel) {
- this.imagePreview = imagePreview;
- this.fileNameLabel = fileNameLabel;
- int pos = imagePreview.fileName.lastIndexOf('.');
- if (pos != -1) {
- this.name = imagePreview.fileName.substring(0, pos);
- this.extension = imagePreview.fileName.substring(pos);
- } else {
- this.name = imagePreview.fileName;
- this.extension = "";
- }
-
- setStyleName("imagare-stage-edit-panel");
- fileNameBox = new TextBox();
- fileNameBox.setStyleName("imagare-stage-input");
- fileNameBox.setValue(name);
- add(fileNameBox);
- add(new Label(extension));
-
- fileNameBox.addBlurHandler(
- new BlurHandler() {
- @Override
- public void onBlur(BlurEvent event) {
- saveChanges();
- }
- });
-
- fileNameBox.addKeyDownHandler(
- new KeyDownHandler() {
- @Override
- public void onKeyDown(KeyDownEvent event) {
- if (event.getNativeKeyCode() == KEY_ESCAPE) {
- discardChanges();
- } else if (event.getNativeKeyCode() == KEY_ENTER) {
- saveChanges();
- }
- }
- });
- }
-
- private void saveChanges() {
- imagePreview.fileName = fileNameBox.getValue() + extension;
- fileNameLabel.setText(fileNameBox.getValue() + extension);
- fileNameLabel.setVisible(true);
- removeFromParent();
- }
-
- private void discardChanges() {
- fileNameLabel.setVisible(true);
- removeFromParent();
- }
-
- void focusAndSelectAll() {
- fileNameBox.setFocus(true);
- fileNameBox.selectAll();
- }
- }
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadedImagesPanel.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadedImagesPanel.java
deleted file mode 100644
index 2e010c3..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadedImagesPanel.java
+++ /dev/null
@@ -1,286 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// 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.googlesource.gerrit.plugins.imagare.client;
-
-import com.google.gerrit.plugin.client.Plugin;
-import com.google.gerrit.plugin.client.rpc.NoContent;
-import com.google.gerrit.plugin.client.rpc.RestApi;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.dom.client.MouseOutEvent;
-import com.google.gwt.event.dom.client.MouseOutHandler;
-import com.google.gwt.event.dom.client.MouseOverEvent;
-import com.google.gwt.event.dom.client.MouseOverHandler;
-import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.Image;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.PopupPanel;
-import com.google.gwt.user.client.ui.VerticalPanel;
-import com.google.gwtexpui.clippy.client.CopyableLabel;
-import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
-
-public class UploadedImagesPanel extends FlowPanel {
-
- private Label uploadedImagesLabel;
- private PopupPanel popup;
-
- UploadedImagesPanel() {
- setStyleName("imagare-uploaded-images-panel");
-
- uploadedImagesLabel = new Label("Uploaded Images:");
- uploadedImagesLabel.setStyleName("imagare-uploaded-images-label");
- uploadedImagesLabel.setVisible(false);
- add(uploadedImagesLabel);
-
- popup = new PopupPanel();
- popup.setVisible(false);
- }
-
- void add(final String url) {
- uploadedImagesLabel.setVisible(true);
- insert(new ImagePreview(url), 1);
- }
-
- private class ImagePreview extends VerticalPanel {
- private final Image img;
- private final Image fullScreenIcon;
- private Timer fullScreenIconHideTimer;
- private final Image deleteIcon;
- private Timer deleteIconHideTimer;
-
- ImagePreview(final String url) {
- setStyleName("imagare-uploaded-image-preview-panel");
-
- int revIndex = url.indexOf("/rev/");
- int projectIndex = url.lastIndexOf('/', revIndex - 1);
- int fileIndex = url.indexOf('/', revIndex + 5);
- final String project = url.substring(projectIndex + 1, revIndex);
- final String ref = url.substring(revIndex + 5, fileIndex);
- final String fileName = url.substring(fileIndex + 1).replaceAll("\\+", " ");
- Label fileNameLabel = new Label(fileName);
- fileNameLabel.setStyleName("imagare-uploaded-image-title");
- add(fileNameLabel);
-
- img = new Image(url);
- img.setStyleName("imagare-uploaded-image-preview");
- add(img);
-
- fullScreenIcon = new Image(ImagarePlugin.RESOURCES.fullScreen());
- fullScreenIcon.setStyleName("imagare-fullscreen-icon");
- fullScreenIcon.setTitle("Full Screen");
- fullScreenIcon.setVisible(false);
- add(fullScreenIcon);
-
- deleteIcon = new Image(ImagarePlugin.RESOURCES.delete());
- deleteIcon.setStyleName("imagare-delete-icon");
- deleteIcon.setTitle("Delete Image");
- deleteIcon.setVisible(false);
- add(deleteIcon);
-
- img.addMouseOverHandler(
- new MouseOverHandler() {
- @Override
- public void onMouseOver(MouseOverEvent event) {
- if (!popup.isVisible()) {
- Image previewImg = new Image(url);
- previewImg.setStyleName("imagare-image-popup");
- previewImg
- .getElement()
- .setAttribute(
- "style",
- previewImg.getElement().getAttribute("style")
- + "position: absolute; top: "
- + (img.getAbsoluteTop() + img.getHeight() + 20)
- + "px; "
- + "left: "
- + img.getAbsoluteLeft()
- + "px;");
- popup.add(previewImg);
-
- popup.show();
- popup.setVisible(true);
- }
-
- cancelHideFullScreenIcon();
- fullScreenIcon
- .getElement()
- .setAttribute(
- "style",
- fullScreenIcon.getElement().getAttribute("style")
- + "position: absolute; top: "
- + img.getAbsoluteTop()
- + "px; "
- + "left: "
- + img.getAbsoluteLeft()
- + "px;");
- fullScreenIcon.setVisible(true);
-
- cancelHideDeleteIcon();
- deleteIcon
- .getElement()
- .setAttribute(
- "style",
- deleteIcon.getElement().getAttribute("style")
- + "position: absolute; top: "
- + img.getAbsoluteTop()
- + "px; "
- + "left: "
- + (img.getAbsoluteLeft() + fullScreenIcon.getWidth())
- + "px;");
- deleteIcon.setVisible(true);
- }
- });
- img.addMouseOutHandler(
- new MouseOutHandler() {
- @Override
- public void onMouseOut(MouseOutEvent event) {
- popup.setVisible(false);
- popup.clear();
- hideFullScreenIcon();
- hideDeleteIcon();
- }
- });
-
- fullScreenIcon.addMouseOverHandler(
- new MouseOverHandler() {
- @Override
- public void onMouseOver(MouseOverEvent event) {
- cancelHideFullScreenIcon();
- cancelHideDeleteIcon();
- }
- });
-
- fullScreenIcon.addMouseOutHandler(
- new MouseOutHandler() {
- @Override
- public void onMouseOut(MouseOutEvent event) {
- hideFullScreenIcon();
- hideDeleteIcon();
- }
- });
-
- fullScreenIcon.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- Window.open(url, "_blank", "");
- popup.setVisible(false);
- popup.clear();
- }
- });
-
- deleteIcon.addMouseOverHandler(
- new MouseOverHandler() {
- @Override
- public void onMouseOver(MouseOverEvent event) {
- cancelHideFullScreenIcon();
- cancelHideDeleteIcon();
- }
- });
-
- deleteIcon.addMouseOutHandler(
- new MouseOutHandler() {
- @Override
- public void onMouseOut(MouseOutEvent event) {
- hideDeleteIcon();
- hideFullScreenIcon();
- }
- });
-
- deleteIcon.addClickHandler(
- new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- new ConfirmationDialog(
- "Delete Image",
- new SafeHtmlBuilder()
- .append("Are you sure you want to delete '" + fileName + "'?")
- .br()
- .br(),
- new ConfirmationCallback() {
- @Override
- public void onOk() {
- new RestApi("projects")
- .view(project)
- .view(Plugin.get().getPluginName(), "images")
- .view(ref)
- .delete(
- new AsyncCallback<NoContent>() {
- @Override
- public void onSuccess(NoContent info) {
- UploadedImagesPanel.this.remove(ImagePreview.this);
- uploadedImagesLabel.setVisible(
- UploadedImagesPanel.this.getWidgetCount() > 1);
-
- popup.setVisible(false);
- popup.clear();
- }
-
- @Override
- public void onFailure(Throwable caught) {
- // never invoked
- }
- });
- }
- })
- .center();
- }
- });
-
- CopyableLabel copyLabel = new CopyableLabel(url);
- copyLabel.setStyleName("imagare-uploaded-copy-label");
- add(copyLabel);
- }
-
- private void hideFullScreenIcon() {
- fullScreenIconHideTimer =
- new Timer() {
- @Override
- public void run() {
- fullScreenIcon.setVisible(false);
- }
- };
- fullScreenIconHideTimer.schedule(20);
- }
-
- private void cancelHideFullScreenIcon() {
- if (fullScreenIconHideTimer != null) {
- fullScreenIconHideTimer.cancel();
- fullScreenIconHideTimer = null;
- }
- }
-
- private void hideDeleteIcon() {
- deleteIconHideTimer =
- new Timer() {
- @Override
- public void run() {
- deleteIcon.setVisible(false);
- }
- };
- deleteIconHideTimer.schedule(20);
- }
-
- private void cancelHideDeleteIcon() {
- if (deleteIconHideTimer != null) {
- deleteIconHideTimer.cancel();
- deleteIconHideTimer = null;
- }
- }
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/delete.png b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/delete.png
deleted file mode 100644
index ea03150..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/delete.png
+++ /dev/null
Binary files differ
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/fullscreen.png b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/fullscreen.png
deleted file mode 100644
index ffdabd4..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/fullscreen.png
+++ /dev/null
Binary files differ
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/image.png b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/image.png
deleted file mode 100644
index 68da502..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/image.png
+++ /dev/null
Binary files differ
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/public/imagare.css b/src/main/java/com/googlesource/gerrit/plugins/imagare/public/imagare.css
deleted file mode 100644
index 5d0aa57..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/public/imagare.css
+++ /dev/null
@@ -1,150 +0,0 @@
-.imagare-image-upload-screen, .imagare-uploaded-images-panel,
-imagare-upload-stage-panel, .imagare-config-screen {
- width: 100%;
- border-spacing: 0px 5px;
-}
-
-.imagare-uploaded-images-panel {
- width: 1000px;
-}
-
-.imagare-label-panel {
- margin-bottom: 10px;
-}
-
-.imagare-label-panel td {
- vertical-align: middle !important;
-}
-
-.imagare-label-panel td div {
- margin-right: 5px;
-}
-
-.imagare-uploaded-images-panel td {
- vertical-align: middle !important;
-}
-
-.imagare-menu-panel {
- width: 350px;
- background-color: #F6F6F6;
- margin-bottom: 15px;
-}
-
-.imagare-menu-panel img {
- float: right;
- margin-top: 1px;
- margin-left: 3px;
- margin-right: 1px;
-}
-
-.imagare-image-upload-panel {
- width: 350px;
- border: 1px solid #B3B2B2;
- border-spacing: 5px 5px;
- background-color: #EEE;
-}
-
-.imagare-image-upload-panel td {
- text-align: center;
- font-size: 18px;
- margin-bottom: 3px;
-}
-
-.imagare-image-upload-panel div {
- color: #999;
-}
-
-.imagare-uploaded-images-label,
-.imagare-staged-images-label {
- font-size: 20px;
-}
-
-.imagare-image-preview {
- max-width: 150px;
- max-height: 100px;
- margin: 5px;
- border: 1px solid #B3B2B2;
-}
-
-.imagare-stage-image-title,
-.imagare-uploaded-image-title {
- margin-top: 10px;
- max-width: 150px;
- font-size: 12px;
- font-weight: bold;
-}
-
-.imagare-uploaded-image-title {
- max-width: 150px;
-}
-
-.imagare-stage-edit-panel td {
- vertical-align: middle !important;
-}
-
-.imagare-stage-input {
- margin-top: 10px;
- font-size: 12px;
-}
-
-.imagare-stage-image-preview,
-.imagare-uploaded-image-preview {
- max-width: 150px;
- max-height: 100px;
- border: 1px solid #B3B2B2;
-}
-
-.imagare-uploaded-copy-label span {
- max-width: 150px;
- width: 500px;
- white-space: nowrap;
- display: inline-block;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.imagare-image-popup {
- border: 1px solid #B3B2B2;
- max-width: 500px;
- max-height: 500px;
-}
-
-.imagare-stage-image-preview-panel,
-.imagare-uploaded-image-preview-panel {
- display: inline-block;
- margin-left: 10px;
- margin-right: 10px;
-}
-
-.imagare-stage-image-preview-panel td,
-.imagare-uploaded-image-preview-panel td {
- text-align: center;
-}
-
-.imagare-staged-images-panel {
- width: 1000px;
-}
-
-.imagare-stage-label {
- font-size: 12px;
- max-width: 150px;
-}
-
-.imagare-save-button {
- margin-bottom: 10px;
-}
-
-.imagare-upload-button, .imagare-clean-button {
- margin-right: 10px;
- margin-top: 10px;
- margin-bottom: 10px;
-}
-
-.imagare-delete-icon,
-.imagare-fullscreen-icon {
- z-index: 100;
- width: 16px;
- height: 16px;
- background-color: #FFF !important;
- border: 1px solid #B3B2B2;
-}
diff --git a/src/main/resources/static/gr-imagare-inline.html b/src/main/resources/static/gr-imagare-inline.html
new file mode 100644
index 0000000..9b698fa
--- /dev/null
+++ b/src/main/resources/static/gr-imagare-inline.html
@@ -0,0 +1,19 @@
+ <!--
+@license
+Copyright (C) 2019 The Android Open Source Project
+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.
+-->
+
+<dom-module id="gr-imagare-inline">
+ <template>
+ </template>
+ <script src="gr-imagare-inline.js"></script>
+</dom-module>
diff --git a/src/main/resources/static/gr-imagare-inline.js b/src/main/resources/static/gr-imagare-inline.js
new file mode 100644
index 0000000..3001252
--- /dev/null
+++ b/src/main/resources/static/gr-imagare-inline.js
@@ -0,0 +1,189 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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.
+
+(function () {
+ 'use strict';
+
+ const LINK_DECORATIONS = {
+ NONE: 1,
+ INLINE: 2,
+ TOOLTIP: 3,
+ };
+
+ Polymer({
+ is: 'gr-imagare-inline',
+
+ properties: {
+ _expandedObserver: MutationObserver,
+ _messageAddedObserver: MutationObserver,
+ _messages: Object,
+ _link_decoration: Number,
+ _pattern: String,
+ _decorator_fn: Function,
+ },
+
+ attached() {
+ this._getAccountPrefs().then(() => {
+ if (this._link_decoration === LINK_DECORATIONS.NONE) {
+ return;
+ }
+
+ this._expandedObserver = new MutationObserver(mutations => {
+ mutations.forEach(mut => {
+ if (!mut.target.classList.contains('expanded')){
+ return;
+ }
+ let links = this._getLinksFromMessage(mut.target);
+
+ if (!links) {
+ return;
+ }
+
+ for (const link of links) {
+ this._decorator_fn(link);
+ }
+ });
+ });
+
+ this._messageAddedObserver = new MutationObserver(mutations => {
+ mutations.forEach(mut => {
+ mut.addedNodes.forEach(node => {
+ if (node.tagName === "GR-MESSAGE") {
+ this._addExpandedObservers(node);
+ }
+ });
+ });
+ });
+
+ this._messageAddedObserver.observe(
+ document.getElementsByTagName('gr-messages-list')[0],
+ {
+ childList: true,
+ });
+
+ this._addObserversToMessages();
+ });
+ },
+
+ detached() {
+ this._expandedObserver.disconnect();
+ this._messageAddedObserver.disconnect();
+ },
+
+ _addObserversToMessages() {
+ this._messages = this._getMessages();
+
+ if (!this._messages) {
+ return;
+ }
+
+ for (const message of this._messages) {
+ this._addExpandedObservers(message);
+ }
+ },
+
+ _addExpandedObservers(message) {
+ this._expandedObserver.observe(message, {
+ attributes: true,
+ attributeOldValue: true,
+ attributFilter: ['class'],
+ });
+ },
+
+ _getAccountPrefs() {
+ return this.plugin.restApi('/accounts/self/imagare~preference')
+ .get('')
+ .then(prefs => {
+ if (!prefs || !prefs.link_decoration) {
+ this._link_decoration = LINK_DECORATIONS.NONE;
+ this._pattern = '.*';
+ } else {
+ this._link_decoration = LINK_DECORATIONS[prefs.link_decoration.toUpperCase()];
+ this._pattern = prefs.pattern || '.*';
+ }
+
+ switch (this._link_decoration) {
+ case LINK_DECORATIONS.INLINE:
+ this._decorator_fn = this._insertImage.bind(this);
+ break;
+ case LINK_DECORATIONS.TOOLTIP:
+ this._decorator_fn = this._addTooltip.bind(this);
+ break;
+ case LINK_DECORATIONS.NONE:
+ default:
+ this._decorator_fn = () => {};
+ }
+ });
+ },
+
+ _getMessages() {
+ let messageList = document.getElementsByTagName('gr-messages-list')[0];
+ if (messageList) {
+ return messageList.getElementsByTagName('gr-message');
+ }
+ },
+
+ _getLinksFromMessage(message) {
+ let links = [];
+ let linkedTexts = message.getElementsByTagName('gr-linked-text');
+ for (const e of linkedTexts) {
+ let aTags = e.getElementsByTagName('a');
+ if (aTags && aTags.length > 0){
+ for (const a of aTags){
+ if (a.getElementsByTagName('img').length > 0) {
+ continue;
+ }
+ if (!a.href.match(this._pattern)) {
+ continue;
+ }
+
+ links = links.concat(a);
+ }
+ }
+ }
+ return links.length > 0 ? links : null;
+ },
+
+ _createImage(url) {
+ let img = document.createElement('img');
+ img.setAttribute("src", url);
+ img.setAttribute("style", "max-width: 100%; height: auto;");
+
+ return img;
+ },
+
+ _insertImage(link) {
+ if (!link) {
+ return;
+ }
+
+ link.replaceWith(this._createImage(link.href));
+ },
+
+ _addTooltip(link) {
+ if (!link) {
+ return;
+ }
+
+ link.onmouseover = (event) => {
+ let img = this._createImage(link.href);
+ img.onmouseout = (event) => {
+ event.target.replaceWith(link);
+ }
+
+ event.target.replaceWith(img);
+ }
+ },
+ });
+})();
diff --git a/src/main/resources/static/gr-imagare-list-item.html b/src/main/resources/static/gr-imagare-list-item.html
new file mode 100644
index 0000000..2f66329
--- /dev/null
+++ b/src/main/resources/static/gr-imagare-list-item.html
@@ -0,0 +1,135 @@
+<!--
+@license
+Copyright (C) 2019 The Android Open Source Project
+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.
+-->
+
+<dom-module id="gr-imagare-list-item">
+ <template>
+ <style include="shared-styles"></style>
+ <style include="gr-subpage-styles"></style>
+ <style>
+ div.image-panel {
+ margin: 2em auto;
+ max-width: 50em;
+ height: 150px;
+ }
+
+ div.title {
+ float: left;
+ width: 30%;
+ height: 100%;
+ }
+
+ div.value {
+ text-align: center;
+ float: right;
+ width: 70%;
+ height: 100%;
+ }
+
+ div.imageName {
+ font-weight: bold;
+ padding: 1em;
+ }
+
+ a {
+ display: block;
+ }
+
+ .ellipsis {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ float: left;
+ width: 80%;
+ }
+
+ img {
+ width: 100%;
+ height: auto;
+ max-height: 100%;
+ max-width: 80%;
+ object-fit: contain;
+ }
+
+ #editButton {
+ box-shadow: none;
+ }
+ </style>
+ <div class="image-panel">
+ <div class="title">
+ <img id="thumbnail">
+ </div>
+ <div id="staging" class="value">
+ <div class="imageName">
+ <iron-input bind-value="{{imageName}}">
+ <input id="imageNameInput" value="{{imageName::input}}" type="text"
+ disabled="[[!_editing]]" placeholder$="[[imageName]]">
+ </iron-input>
+ <gr-button id="editButton" on-click="_handleEditImage" hidden="[[_editing]]">
+ Edit
+ </gr-button>
+ <gr-button id="saveButton" on-click="_handleSaveName" hidden="[[!_editing]]">
+ Save
+ </gr-button>
+ <gr-button id="cancelRenameButton" on-click="_handleCancelRenameName"
+ hidden="[[!_editing]]">
+ Cancel
+ </gr-button>
+ </div>
+ <div>
+ <section>
+ <gr-button id="uploadButton"
+ on-click="_handleUploadImage"
+ disabled="[[_editing]]">
+ Upload
+ </gr-button>
+ <gr-button id="cleanButton"
+ on-click="_handleClearImage">
+ Clear
+ </gr-button>
+ </section>
+ </div>
+ </div>
+ <div id="uploading" class="value">
+ <div class="imageName">
+ [[imageName]]
+ </div>
+ <div>
+ <a class="ellipsis" href="[[imageUrl]]">[[imageUrl]]</a>
+ <gr-copy-clipboard has-tooltip button-title="Copy URL to Clipboard"
+ hide-input text="[[imageUrl]]">
+ </gr-copy-clipboard>
+ </div>
+ <gr-button id="deleteButton"
+ on-click="_openDeleteDialog">
+ Delete
+ </gr-button>
+ <gr-overlay id="deleteOverlay" with-backdrop>
+ <gr-dialog id="deleteDialog"
+ class="confirmDialog"
+ confirm-label="Delete"
+ confirm-on-enter
+ on-confirm="_handleDeleteImage">
+ <div class="header" slot="header">
+ Delete Image
+ </div>
+ <div class="main" slot="main">
+ Are you sure you want to delete '[[imageName]]'?
+ </div>
+ </gr-dialog>
+ </gr-overlay>
+ </div>
+ </div>
+ </template>
+ <script src="gr-imagare-list-item.js"></script>
+</dom-module>
diff --git a/src/main/resources/static/gr-imagare-list-item.js b/src/main/resources/static/gr-imagare-list-item.js
new file mode 100644
index 0000000..5f1cffe
--- /dev/null
+++ b/src/main/resources/static/gr-imagare-list-item.js
@@ -0,0 +1,107 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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.
+
+(function () {
+ 'use strict';
+
+ Polymer({
+ is: 'gr-imagare-list-item',
+
+ properties: {
+ imageUrl: {
+ type: String,
+ reflectToAttribute: true,
+ },
+ imageName: {
+ type: String,
+ reflectToAttribute: true,
+ },
+ imageData: {
+ type: String,
+ reflectToAttribute: true,
+ },
+ uploaded: {
+ type: Boolean,
+ observer: '_uploadedChanged',
+ reflectToAttribute: true,
+ },
+ _originalImageName: String,
+ _editing: {
+ type: Boolean,
+ value: false,
+ },
+ _imageSrc: String,
+ },
+
+ attached() {
+ this._originalImageName = this.imageName;
+ this._setImage();
+ },
+
+ _handleCancelRenameName() {
+ this.imageName = this._originalImageName;
+ this._editing = false;
+ },
+
+ _handleClearImage() {
+ this.fire("clear");
+ },
+
+ _handleDeleteImage() {
+ this.fire("delete");
+ },
+
+ _handleEditImage() {
+ this._editing = true;
+ },
+
+ _handleSaveName() {
+ this._editing = false;
+
+ if (this._originalImageName === this.imageName) {
+ return;
+ }
+
+ let oldFileType = this._originalImageName.split('.').pop();
+ let newFileType = this.imageName.split('.').pop();
+ if (oldFileType !== newFileType) {
+ this.imageName += `.${oldFileType}`;
+ }
+
+ this.fire("editName", {oldName: this._originalImageName, newName: this.imageName});
+ },
+
+ _handleUploadImage() {
+ this.fire("upload");
+ },
+
+ _openDeleteDialog() {
+ this.$.deleteOverlay.open();
+ },
+
+ _setImage() {
+ if (this.uploaded) {
+ this.$.thumbnail.setAttribute('src', this.imageUrl);
+ } else {
+ this.$.thumbnail.setAttribute('src', this.imageData);
+ }
+ },
+
+ _uploadedChanged(uploaded) {
+ this.$.uploading.hidden = !uploaded;
+ this.$.staging.hidden = uploaded;
+ this._setImage();
+ },
+ });
+})();
diff --git a/src/main/resources/static/gr-imagare-pref-menu-item.html b/src/main/resources/static/gr-imagare-pref-menu-item.html
new file mode 100644
index 0000000..ee8b989
--- /dev/null
+++ b/src/main/resources/static/gr-imagare-pref-menu-item.html
@@ -0,0 +1,29 @@
+<!--
+@license
+Copyright (C) 2019 The Android Open Source Project
+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.
+-->
+
+<dom-module id="gr-imagare-pref-menu-item">
+ <template>
+ <style include="shared-styles"></style>
+ <style include="gr-page-nav-styles">
+ li {
+ padding-left: 1.5em;
+ padding-right: 1.5em;
+ }
+ </style>
+ <li class="navStyles">
+ <a href="#ImagarePreferences">Imagare Preferences</a>
+ </li>
+ </template>
+ <script src="gr-imagare-pref-menu-item.js"></script>
+</dom-module>
diff --git a/src/main/resources/static/gr-imagare-pref-menu-item.js b/src/main/resources/static/gr-imagare-pref-menu-item.js
new file mode 100644
index 0000000..3e1a7b0
--- /dev/null
+++ b/src/main/resources/static/gr-imagare-pref-menu-item.js
@@ -0,0 +1,21 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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.
+
+(function () {
+ 'use strict';
+
+ Polymer({
+ is: 'gr-imagare-pref-menu-item',
+ });
+})();
diff --git a/src/main/resources/static/gr-imagare-preferences.html b/src/main/resources/static/gr-imagare-preferences.html
new file mode 100644
index 0000000..ae26388
--- /dev/null
+++ b/src/main/resources/static/gr-imagare-preferences.html
@@ -0,0 +1,60 @@
+<!--
+@license
+Copyright (C) 2019 The Android Open Source Project
+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.
+-->
+
+<dom-module id="gr-imagare-preferences">
+ <template>
+ <style include="shared-styles"></style>
+ <style include="gr-form-styles"></style>
+ <h2 id="ImagarePreferences">Imagare Preferences</h2>
+ <fieldset class="gr-form-styles">
+ <section>
+ <span class="title">Link Decoration</span>
+ <span class="value">
+ <gr-select bind-value="{{_linkDecoration}}">
+ <select on-change="_handlePrefsChanged">
+ <option value="NONE">none</option>
+ <option value="INLINE">inline</option>
+ <option value="TOOLTIP">tooltip</option>
+ </select>
+ </gr-select>
+ </span>
+ </section>
+ <section>
+ <span class="title">Default Project</span>
+ <span class="value">
+ <gr-autocomplete id="imagareDefaultProjectInput" text="{{_defaultImageProject}}"
+ value="{{_defaultImageProject}}" query="[[_query]]"
+ on-commit="_handlePrefsChanged" on-keyup="_handlePrefsChanged">
+ [[_defaultImageProject]]
+ </gr-autocomplete>
+ </span>
+ </section>
+ <section>
+ <span class="title">Stage images before upload</span>
+ <span class="value">
+ <input id="stageImages"
+ type="checkbox"
+ checked$="[[_stageImages]]"
+ on-change="_handleStageImagesChanged">
+ </span>
+ </section>
+ <gr-button id="saveButton"
+ on-tap="_handleImagarePrefsSave"
+ disabled="[[!_prefsChanged]]">
+ Save Changes
+ </gr-button>
+ </fieldset>
+ </template>
+ <script src="gr-imagare-preferences.js"></script>
+</dom-module>
diff --git a/src/main/resources/static/gr-imagare-preferences.js b/src/main/resources/static/gr-imagare-preferences.js
new file mode 100644
index 0000000..d1f868f
--- /dev/null
+++ b/src/main/resources/static/gr-imagare-preferences.js
@@ -0,0 +1,101 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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.
+
+(function () {
+ 'use strict';
+
+ Polymer({
+ is: 'gr-imagare-preferences',
+
+ properties: {
+ _defaultImageProject: String,
+ _linkDecoration: String,
+ _stageImages: Boolean,
+ _prefsChanged: {
+ type: Boolean,
+ value: false
+ },
+ _query: {
+ type: Function,
+ value() {
+ return this._queryProjects.bind(this);
+ },
+ },
+ },
+
+ attached() {
+ this._getUserPreferences();
+ },
+
+ _getUserPreferences() {
+ this.plugin.restApi('/accounts/self/')
+ .get(`imagare~preference`)
+ .then(config => {
+ if (!config) {
+ return;
+ }
+
+ this._linkDecoration = config.link_decoration;
+ this._defaultImageProject = config.default_project;
+ this._stageImages = config.stage;
+ }).catch(response => {
+ this.fire('show-error', {message: response});
+ });
+ },
+
+ _handleImagarePrefsSave(){
+ this.plugin.restApi('/accounts/self/')
+ .put(`imagare~preference`, {
+ default_project: this._defaultImageProject,
+ link_decoration: this._linkDecoration,
+ stage: this._stageImages,
+ }).then(() => {
+ this._prefsChanged = false;
+ }).catch(response => {
+ this.fire('show-error', {message: response});
+ });
+ },
+
+ _handlePrefsChanged() {
+ this._prefsChanged = true;
+ },
+
+ _handleStageImagesChanged(event){
+ this._handlePrefsChanged();
+ this._stageImages = event.target.checked;
+ },
+
+ _queryProjects(input) {
+ let query;
+ if (!input || input === this._defaultImageProject) {
+ query = '';
+ } else {
+ query = `?prefix=${input}`;
+ }
+
+ return this.plugin.restApi('/a/projects/').get(query)
+ .then(response => {
+ const projects = [];
+ for (const key in response) {
+ if (!response.hasOwnProperty(key)) { continue; }
+ projects.push({
+ name: key,
+ value: decodeURIComponent(response[key].id),
+ });
+ }
+ return projects;
+ });
+ },
+ });
+})();
diff --git a/src/main/resources/static/gr-imagare-upload.html b/src/main/resources/static/gr-imagare-upload.html
new file mode 100644
index 0000000..814ade2
--- /dev/null
+++ b/src/main/resources/static/gr-imagare-upload.html
@@ -0,0 +1,132 @@
+<!--
+@license
+Copyright (C) 2019 The Android Open Source Project
+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.
+-->
+
+<link rel="import"
+ href="./gr-imagare-list-item.html">
+
+<dom-module id="gr-imagare-upload">
+ <template>
+ <style include="shared-styles"></style>
+ <style include="gr-subpage-styles"></style>
+ <style include="gr-form-styles"></style>
+ <style>
+ div.image-upload {
+ margin: 2em auto;
+ max-width: 50em;
+ }
+
+ h1#title {
+ margin-bottom: 1em;
+ }
+
+ div#dragDropArea {
+ padding: 2em 10em;
+ border: 2px dashed #ccc;
+ border-radius: 1em;
+ text-align: center;
+ }
+
+ div#dragDropArea>p {
+ font-weight: bold;
+ text-transform: uppercase;
+ padding: 0.25em;
+ }
+
+ div#dragDropArea>p.or {
+ color: #ccc;
+ }
+
+ input#imagareImagePathInput {
+ border: 0;
+ clip: rect(0, 0, 0, 0);
+ height: 1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute !important;
+ white-space: nowrap;
+ width: 1px;
+ }
+ </style>
+ <div class="image-upload">
+ <main class="gr-form-styles read-only">
+ <h1 id="title">Image Upload</h1>
+ <div id="loading"
+ class$="[[_computeLoadingClass(_loading)]]">
+ Loading...
+ </div>
+ <div id="form"
+ class$="[[_computeLoadingClass(_loading)]]">
+ <fieldset>
+ <h2>Settings</h2>
+ <section>
+ The user preferences for the image upload can be changed
+ <a href="[[_computeSettingsUrl()]]">here</a>.
+ </section>
+ <section>
+ <span class="title">Project</span>
+ <span class="value">
+ <gr-autocomplete id="imagareProjectInput" text="{{_imageProject}}"
+ value="{{_imageProject}}" query="[[_query]]">
+ [[_defaultImageProject]]
+ </gr-autocomplete>
+ </span>
+ </section>
+ </fieldset>
+ <fieldset>
+ <h2>Image Selection</h2>
+ <section>
+ <div id="dragDropArea" contenteditable="true" on-paste="_handlePaste"
+ on-drop="_handleDrop" on-keypress="_handleKeyPress">
+ <p>Drag and drop image here</p>
+ <p class="or">or</p>
+ <p>paste it here</p>
+ <p class="or">or</p>
+ <p>
+ <iron-input>
+ <input id="imagareImagePathInput"
+ type="file"
+ on-change="_handleImagePathChanged"
+ slot="input"
+ multiple>
+ </iron-input>
+ <label for="imagareImagePathInput">
+ <gr-button>
+ Browse
+ </gr-button>
+ </label>
+ </p>
+ </div>
+ </section>
+ </fieldset>
+ <fieldset id="imageListContainer" hidden>
+ <h2>Images</h2>
+ <fieldset id="imageList"></fieldset>
+ <section>
+ <gr-button id="uploadButton"
+ on-click="_handleUploadAllImages"
+ disabled="[[_allUploaded]]">
+ Upload All
+ </gr-button>
+ <gr-button id="cleanButton"
+ on-click="_handleClearAllImages">
+ Clear List
+ </gr-button>
+ </section>
+ </fieldset>
+ </div>
+ </main>
+ </div>
+ </template>
+ <script src="gr-imagare-upload.js"></script>
+</dom-module>
diff --git a/src/main/resources/static/gr-imagare-upload.js b/src/main/resources/static/gr-imagare-upload.js
new file mode 100644
index 0000000..40150c1
--- /dev/null
+++ b/src/main/resources/static/gr-imagare-upload.js
@@ -0,0 +1,374 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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.
+
+(function () {
+ 'use strict';
+
+ function preventDefaultFn(event) {
+ event.preventDefault();
+ }
+
+ Polymer({
+ is: 'gr-imagare-upload',
+
+ properties: {
+ _loading: {
+ type: Boolean,
+ value: true,
+ },
+ _allUploaded: {
+ type: Boolean,
+ value: false,
+ },
+ _imageProject: String,
+ _defaultImageProject: String,
+ _images: {
+ type: Map,
+ value: () => new Map(),
+ },
+ _stageImages: {
+ type: Boolean,
+ value: true,
+ },
+ _undefinedFileCounter: {
+ type: Number,
+ value: 0,
+ },
+ _query: {
+ type: Function,
+ value() {
+ return this._queryProjects.bind(this);
+ },
+ },
+ },
+
+ listeners: {
+ clear: '_handleClearImage',
+ delete: '_handleDeleteImage',
+ editName: '_handleEditImageName',
+ upload: '_handleUploadImage',
+ },
+
+ attached() {
+ this.fire('title-change', { title: 'Image Upload' });
+
+ window.addEventListener('dragover', preventDefaultFn, false);
+ window.addEventListener('drop', preventDefaultFn, false);
+ this.$.dragDropArea.addEventListener('paste', preventDefaultFn, false);
+
+ this._getUserPreferences();
+ },
+
+ detached() {
+ window.removeEventListener('dragover', preventDefaultFn, false);
+ window.removeEventListener('drop', preventDefaultFn, false);
+ this.$.dragDropArea.removeEventListener('paste', preventDefaultFn, false);
+ },
+
+ _computeFilenameWithCorrectType(filedata, filename) {
+ let realFiletype = filedata.slice(
+ filedata.indexOf('/') + 1,
+ filedata.indexOf(';'));
+
+ let givenFiletype;
+
+ if (filename.indexOf(".") !== -1) {
+ givenFiletype = filename.split('.').pop();
+ }
+
+ if (!givenFiletype || realFiletype !== givenFiletype) {
+ filename += `.${realFiletype}`;
+ }
+
+ return filename;
+ },
+
+ _computeLoadingClass(loading) {
+ return loading ? 'loading' : '';
+ },
+
+ _computeSettingsUrl() {
+ return `${location.origin}/settings#ImagarePreferences`;
+ },
+
+ _computeUploadAllDisabled() {
+ if (this._images) {
+ for (let value of this._images.values()) {
+ if (!value.uploaded) {
+ this._allUploaded = false;
+ return;
+ }
+ }
+ }
+
+ this._allUploaded = true;
+ },
+
+ _createImageObject(name, data, url, list_entry, uploaded, ref) {
+ return {
+ data: data,
+ list_entry: list_entry,
+ name: name,
+ ref: ref,
+ url: url,
+ uploaded: uploaded,
+ }
+ },
+
+ _createListEntry(name, data, url) {
+ let imagePanel = document.createElement('gr-imagare-list-item');
+ imagePanel.setAttribute("image-name", name);
+
+ if (data) {
+ imagePanel.setAttribute("image-data", data);
+ }
+
+ if (url) {
+ imagePanel.setAttribute("image-url", url);
+ imagePanel.uploaded = true;
+ } else {
+ imagePanel.uploaded = false;
+ }
+
+ this.$.imageList.appendChild(imagePanel);
+
+ return imagePanel;
+ },
+
+ _deleteImage(image) {
+ this.plugin.restApi('/projects')
+ .delete(`/${this._imageProject}/imagare~images/${image.ref}`)
+ .then(() => {
+ image.list_entry.remove();
+ this._images.delete(image.name);
+ if (!this.$.imageList.hasChildNodes()) {
+ this.$.imageListContainer.hidden = true;
+ }
+ }).catch(response => {
+ this.fire('show-error', { message: response });
+ });
+ },
+
+ _extractImageRef(url) {
+ return url.split('/').slice(-2)[0];
+ },
+
+ _getUserPreferences() {
+ this.plugin.restApi('/accounts/self/')
+ .get(`imagare~preference`)
+ .then(config => {
+ if (!config) {
+ return;
+ }
+
+ this._defaultImageProject = config.default_project;
+ this._imageProject = config.default_project;
+ this._stageImages = config.stage;
+ this._loading = false;
+ });
+ },
+
+ _handleClearAllImages() {
+ while (this.$.imageList.firstChild) {
+ this.$.imageList.removeChild(this.$.imageList.firstChild);
+ }
+ this.$.imageListContainer.hidden = true;
+
+ this._images.clear()
+ },
+
+ _handleClearImage(event) {
+ event.stopPropagation();
+ this._images.delete(event.target.imageName);
+ event.target.remove();
+ if (!this.$.imageList.hasChildNodes()) {
+ this.$.imageListContainer.hidden = true;
+ }
+ },
+
+ _handleDeleteImage(event) {
+ event.stopPropagation();
+ this._deleteImage(this._images.get(event.target.imageName));
+ },
+
+ _handleDrop(event) {
+ event.preventDefault();
+ event.stopPropagation();
+
+ for (let file of event.dataTransfer.files) {
+ if (!file.type.match('image/.*')) {
+ this.fire('show-error', { message: `No image file: ${file.name}` });
+ }
+ let fr = new FileReader();
+ fr.file = file;
+ fr.onload = fileLoadEvent => this._handleFileLoadEvent(
+ fr.file.name, fileLoadEvent);
+ fr.readAsDataURL(file);
+ }
+ },
+
+ _handleEditImageName(event) {
+ event.stopPropagation();
+ let editedImage = this._images.get(event.detail.oldName);
+ if (this._images.has(event.detail.newName)) {
+ this.fire('show-error', { message: 'An image with the same name was already staged.' });
+ editedImage.list_entry.setAttribute("image-name", event.detail.oldName);
+ } else {
+ editedImage.name = event.detail.newName;
+ this._images.set(editedImage.name, editedImage);
+ this._images.delete(event.detail.oldName);
+ }
+ },
+
+ _handleFileLoadEvent(filename, event) {
+ let correctedFilename = this._computeFilenameWithCorrectType(
+ event.target.result, filename);
+ if (this._stageImages) {
+ this._stageImage(correctedFilename, event.target.result);
+ } else {
+ let image = this._createImageObject(correctedFilename, event.target.result);
+ this._images.set(correctedFilename, image);
+ this._uploadImage(image);
+ }
+ },
+
+ _handleKeyPress(event) {
+ let ctrlDown = event.ctrlKey || event.metaKey;
+ if (!ctrlDown) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ },
+
+ _handleImagePathChanged(event) {
+ for (let file of event.target.files) {
+ let fr = new FileReader();
+ fr.file = file;
+ fr.onload = fileLoadEvent => this._handleFileLoadEvent(
+ fr.file.name, fileLoadEvent);
+ fr.readAsDataURL(file);
+ }
+
+ event.target.value = '';
+ },
+
+ _handlePaste(event) {
+ let clipboardData = event.clipboardData || event.originalEvent.clipboardData;
+ let items = clipboardData.items;
+ if (JSON.stringify(items)) {
+ let blob;
+ for (let item of items) {
+ if (item.type.indexOf("image") === 0) {
+ blob = item.getAsFile();
+ }
+ }
+ if (blob) {
+ let fr = new FileReader();
+ fr.onload = fileLoadEvent => {
+ let filename = `undefined-${this._undefinedFileCounter}`;
+ this._undefinedFileCounter++;
+ this._handleFileLoadEvent(filename, fileLoadEvent);
+ };
+ fr.readAsDataURL(blob);
+ } else {
+ event.preventDefault();
+ this.fire('show-error', { message: `No image file` });
+ }
+ }
+ },
+
+ _handleUploadAllImages() {
+ for (let image of this._images.values()) {
+ this._uploadImage(image);
+ }
+ },
+
+ _handleUploadImage(event) {
+ event.stopPropagation();
+ let image = this._createImageObject(
+ event.target.imageName,
+ event.target.imageData,
+ null,
+ event.target);
+ this._images.set(image.name, image);
+ this._uploadImage(image);
+ },
+
+ _queryProjects(input) {
+ let query;
+ if (!input || input === this._defaultImageProject) {
+ query = '';
+ } else {
+ query = `?prefix=${input}`;
+ }
+
+ return this.plugin.restApi('/a/projects/').get(query)
+ .then(response => {
+ const projects = [];
+ for (const key in response) {
+ if (!response.hasOwnProperty(key)) { continue; }
+ projects.push({
+ name: key,
+ value: decodeURIComponent(response[key].id),
+ });
+ }
+ return projects;
+ });
+ },
+
+ _stageImage(name, data) {
+ if (this._images.has(name)) {
+ let fileName = name.slice(0, name.lastIndexOf('.'));
+ let fileExtension = name.slice(name.lastIndexOf('.'));
+ name = `${fileName}-${this._undefinedFileCounter}${fileExtension}`;
+ this._undefinedFileCounter++;
+ }
+ let imagePanel = this._createListEntry(name, data, null);
+ this._images.set(name, this._createImageObject(name, data, null, imagePanel));
+ this.$.imageListContainer.hidden = false;
+ this._computeUploadAllDisabled();
+ },
+
+ _uploadImage(image) {
+ if (image && image.uploaded) {
+ return;
+ }
+
+ this.plugin.restApi('/projects')
+ .post(`/${this._imageProject}/imagare~images`, {
+ image_data: image.data,
+ file_name: image.name,
+ })
+ .then(response => {
+ if (!image.list_entry) {
+ image.list_entry = this._createListEntry(image.name, image.data, response.url);
+ } else {
+ image.list_entry.setAttribute("image-url", response.url);
+ image.list_entry.uploaded = true;
+ }
+
+ this._images.set(
+ image.name,
+ this._createImageObject(
+ image.name, image.data, response.url, image.list_entry, true,
+ this._extractImageRef(response.url)));
+
+ this.$.imageListContainer.hidden = false;
+ this._computeUploadAllDisabled();
+ }).catch(response => {
+ this.fire('show-error', { message: response });
+ });
+ }
+ });
+})();
diff --git a/src/main/resources/static/imagare.html b/src/main/resources/static/imagare.html
new file mode 100644
index 0000000..2d2077d
--- /dev/null
+++ b/src/main/resources/static/imagare.html
@@ -0,0 +1,38 @@
+<!--
+@license
+Copyright (C) 2019 The Android Open Source Project
+
+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.
+-->
+
+<link rel="import" href="./gr-imagare-inline.html">
+<link rel="import" href="./gr-imagare-preferences.html">
+<link rel="import" href="./gr-imagare-pref-menu-item.html">
+<link rel="import" href="./gr-imagare-upload.html">
+
+<dom-module id="imagare">
+ <script>
+ Gerrit.install(plugin => {
+ if (!window.Polymer) { return; }
+
+ plugin.restApi('/config/server/').get('imagare~config').then(config => {
+ if (config && config.enable_image_server) {
+ plugin.screen('upload', 'gr-imagare-upload');
+ }
+ });
+ plugin.registerCustomComponent('change-view-integration', 'gr-imagare-inline');
+ plugin.registerCustomComponent('settings-screen', 'gr-imagare-preferences');
+ plugin.registerCustomComponent('settings-menu-item', 'gr-imagare-pref-menu-item');
+ });
+ </script>
+</dom-module>
diff --git a/src/main/resources/static/imagare.js b/src/main/resources/static/imagare.js
index 91bec6f..779f1b5 100644
--- a/src/main/resources/static/imagare.js
+++ b/src/main/resources/static/imagare.js
@@ -13,6 +13,11 @@
// limitations under the License.
Gerrit.install(function(self) {
+
+ if (window.Polymer) { return; }
+
+ // The code below is only used by the GWT-UI
+
function onComment(e) {
var prefs = getPrefsFromCookie();
if (prefs !== null) {