// 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; import com.google.collide.client.history.Place; import com.google.collide.client.util.AnimationUtils; import com.google.collide.client.util.ResizeController; import elemental.css.CSSStyleDeclaration; import elemental.events.Event; import elemental.events.EventListener; import elemental.html.Element; /** * Class responsible for managing resizing of the right sidebar. * */ class RightSidebarResizeController extends ResizeController implements RightSidebarExpansionEvent.Handler, RightSidebarToggleEvent.Handler { private static enum ExpansionState { COLLAPSED, EXPANDED, COLLAPSING, EXPANDING } private static final double DURATION = 0.2; private static final int DEFAULT_SIDEBAR_WIDTH = 300; private final int collapsedSplitterRight; private final int defaultEditableContentAreaRight; private final Element splitter; private final Element sidebarArea; private final Element contentArea; private final int splitterWidth; private final Place currentPlace; int oldSidebarWidth; int oldSplitterRight; ExpansionState expansionState = ExpansionState.COLLAPSED; public RightSidebarResizeController(Place currentPlace, CodePerspective.Resources resources, Element splitter, Element sidebarArea, Element contentArea, int splitterWidth, int collapsedSplitterRight, int defaultEditableContentAreaRight) { super(resources, splitter, new ElementInfo(sidebarArea, ResizeProperty.WIDTH), new ElementInfo( splitter, ResizeProperty.RIGHT), new ElementInfo(contentArea, ResizeProperty.RIGHT)); this.currentPlace = currentPlace; this.splitter = splitter; this.sidebarArea = sidebarArea; this.contentArea = contentArea; this.splitterWidth = splitterWidth; this.defaultEditableContentAreaRight = defaultEditableContentAreaRight; oldSplitterRight = this.collapsedSplitterRight = collapsedSplitterRight; } @Override public void onRightSidebarExpansion(RightSidebarExpansionEvent evt) { showSidebar(evt.shouldExpand()); } private void showSidebar(boolean show) { int targetSidebarWidth = oldSidebarWidth; int targetSplitterRight = oldSplitterRight; int targetContentAreaRight = oldSplitterRight + splitterWidth; if (show) { // If we ask to expand, but we are already expanded, do nothing. if (!isAnimating() && !isCollapsed()) { return; } if (targetSidebarWidth <= 0) { targetSidebarWidth = DEFAULT_SIDEBAR_WIDTH; targetSplitterRight = targetSidebarWidth - splitterWidth; targetContentAreaRight = targetSidebarWidth; } } else { // Remember the old sizes if we happen to be expanded. if (!isAnimating() && !isCollapsed()) { oldSidebarWidth = sidebarArea.getClientWidth(); oldSplitterRight = getSplitterOffsetRight(); } // We want to collapse. targetSidebarWidth = splitterWidth; targetSplitterRight = collapsedSplitterRight; targetContentAreaRight = defaultEditableContentAreaRight; } splitter.getStyle().setRight(targetSplitterRight, CSSStyleDeclaration.Unit.PX); splitter.getStyle().setDisplay("none"); final String targetSidebarVisibility = targetSplitterRight <= 0 ? CSSStyleDeclaration.Visibility.HIDDEN : ""; AnimationUtils.backupOverflow(sidebarArea.getStyle()); AnimationUtils.animatePropertySet(sidebarArea, "width", targetSidebarWidth + CSSStyleDeclaration.Unit.PX, DURATION, new EventListener() { @Override public void handleEvent(Event evt) { splitter.getStyle().setDisplay(""); AnimationUtils.restoreOverflow(sidebarArea.getStyle()); sidebarArea.getStyle().setVisibility(targetSidebarVisibility); expansionState = expansionState == ExpansionState.EXPANDING ? ExpansionState.EXPANDED: ExpansionState.COLLAPSED; } }); AnimationUtils.animatePropertySet( contentArea, "right", targetContentAreaRight + CSSStyleDeclaration.Unit.PX, DURATION); sidebarArea.getStyle().setVisibility(""); expansionState = show ? ExpansionState.EXPANDING : ExpansionState.COLLAPSING; } @Override public void onRightSidebarToggled(RightSidebarToggleEvent evt) { showSidebar(isCollapsed()); } @Override public void start() { super.start(); attachDblClickListener(); currentPlace.registerSimpleEventHandler(RightSidebarExpansionEvent.TYPE, this); currentPlace.registerSimpleEventHandler(RightSidebarToggleEvent.TYPE, this); } @Override protected void resizeStarted() { sidebarArea.getStyle().setVisibility(""); super.resizeStarted(); } private void attachDblClickListener() { // Double clicking animates the splitter to hide and show the nav area. // Equivalent to an automated resize. splitter.setOnDblClick(new EventListener() { @Override public void handleEvent(Event evt) { // We just want to toggle. If it is collapsed, we want to expand. currentPlace.fireEvent(new RightSidebarExpansionEvent(isCollapsed())); } }); } private boolean isAnimating() { return expansionState == ExpansionState.EXPANDING || expansionState == ExpansionState.COLLAPSING; } private boolean isCollapsed() { if (isAnimating()) { // Splitter is hidden at this point. return expansionState == ExpansionState.COLLAPSING; } return getSplitterOffsetRight() == collapsedSplitterRight; } private int getSplitterOffsetRight() { return splitter.getOffsetParent().getClientWidth() - splitter.getOffsetLeft() - splitter.getOffsetWidth(); } }