// Copyright 2012 Google Inc. All Rights Reserved.
//
// 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.google.collide.client.code.debugging;
import com.google.collide.client.util.AnimationUtils;
import com.google.collide.client.util.Elements;
import com.google.collide.client.util.dom.DomUtils;
import com.google.collide.mvp.CompositeView;
import com.google.collide.mvp.UiComponent;
import com.google.collide.shared.util.StringUtils;
import com.google.common.annotations.VisibleForTesting;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.ImageResource;
import elemental.events.Event;
import elemental.events.EventListener;
import elemental.html.AnchorElement;
import elemental.html.DivElement;
import elemental.html.Element;
import javax.annotation.Nullable;
/**
* Debugging sidebar pane that is shown when no {@link DebuggerApi} is
* available.
*/
public class DebuggingSidebarNoApiPane extends UiComponent<DebuggingSidebarNoApiPane.View> {
public interface Css extends CssResource {
String root();
String headerLogo();
String headerText();
String button();
String footerText();
}
interface Resources extends ClientBundle {
@Source("DebuggingSidebarNoApiPane.css")
Css workspaceEditorDebuggingSidebarNoApiPaneCss();
@Source("extensionPackage.png")
ImageResource extensionPackage();
}
/**
* Listener of this pane's events.
*/
interface Listener {
void onShouldDisplayNoApiPaneChange();
}
private static class Panel {
private final Element root;
private final AnchorElement button;
private final DivElement footer;
private Panel(Element root, AnchorElement button, DivElement footer) {
this.root = root;
this.button = button;
this.footer = footer;
}
}
/**
* The view for the sidebar call stack pane.
*/
static class View extends CompositeView<Void> {
private final Css css;
private final Panel downloadExtension;
private final Panel browserNotSupported;
View(Resources resources) {
css = resources.workspaceEditorDebuggingSidebarNoApiPaneCss();
downloadExtension = createLayout("",
"Download Debugging Extension",
"Install the Debugging Extension to support debugging in Collide.");
browserNotSupported = createLayout(
"Your browser does not support breakpoint debugging in Collide.",
"Download Google Chrome",
"It's free and installs in seconds.");
setElement(Elements.createDivElement());
}
private Panel createLayout(String headerText, String buttonText, String footerText) {
Element root = Elements.createDivElement(css.root());
if (StringUtils.isNullOrEmpty(headerText)) {
root.appendChild(Elements.createDivElement(css.headerLogo()));
} else {
DomUtils.appendDivWithTextContent(root, css.headerText(), headerText);
}
AnchorElement button = Elements.createAnchorElement();
button.setClassName(css.button());
button.setTextContent(buttonText);
root.appendChild(button);
DivElement footer = DomUtils.appendDivWithTextContent(root, css.footerText(), footerText);
return new Panel(root, button, footer);
}
private void showLayout(@Nullable String extensionUrl) {
hideLayout();
boolean isExtensionSupported = (extensionUrl != null);
final Panel panel = isExtensionSupported ? downloadExtension : browserNotSupported;
getElement().appendChild(panel.root);
panel.button.setTarget(StringUtils.isNullOrEmpty(extensionUrl) ? "_blank" : "");
// TODO: What's the right answer?
panel.button.setHref(StringUtils.ensureNotEmpty(extensionUrl,
"http://www.google.com/url?sa=D&q=http://www.google.com/chrome/"));
if (isExtensionSupported) {
panel.button.addEventListener(Event.CLICK, new EventListener() {
@Override
public void handleEvent(Event evt) {
panel.footer.getStyle().setColor("#000");
panel.footer.getStyle().setOpacity(0.0);
panel.footer.setTextContent("Please accept extension in download bar,"
+ " confirm installation, and then reload the page.");
AnimationUtils.animatePropertySet(
panel.footer, "opacity", "1.0", AnimationUtils.LONG_TRANSITION_DURATION);
}
}, false);
}
}
private void hideLayout() {
downloadExtension.root.removeFromParent();
browserNotSupported.root.removeFromParent();
}
}
static DebuggingSidebarNoApiPane create(View view, DebuggerState debuggerState) {
return new DebuggingSidebarNoApiPane(view, debuggerState);
}
private final DebuggerState debuggerState;
private Listener delegateListener;
private final DebuggerState.DebuggerAvailableListener debuggerAvailableListener =
new DebuggerState.DebuggerAvailableListener() {
@Override
public void onDebuggerAvailableChange() {
displayOrHide();
if (delegateListener != null) {
delegateListener.onShouldDisplayNoApiPaneChange();
}
}
};
@VisibleForTesting
DebuggingSidebarNoApiPane(View view, DebuggerState debuggerState) {
super(view);
this.debuggerState = debuggerState;
debuggerState.getDebuggerAvailableListenerRegistrar().add(debuggerAvailableListener);
displayOrHide();
}
void setListener(Listener listener) {
delegateListener = listener;
}
boolean shouldDisplay() {
return !debuggerState.isDebuggerAvailable();
}
private void displayOrHide() {
if (shouldDisplay()) {
getView().showLayout(debuggerState.getDebuggingExtensionUrl());
} else {
getView().hideLayout();
}
}
}