blob: 5d04e055913bedee29a83a02382cd429666fe98b [file] [log] [blame]
/*
* Copyright 2011 Google Inc.
*
* 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.gwt.user.client.ui;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.event.dom.client.HasScrollHandlers;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Event;
/**
* Abstract parent class for scrollbars implemented using the native browser
* scrollbars.
*/
public abstract class AbstractNativeScrollbar extends Widget implements HasScrollHandlers {
private static int nativeHeight = -1;
private static int nativeWidth = -1;
private static boolean nativeRtl = false;
/**
* Get the height of a native horizontal scrollbar.
*
* <p>
* This method assumes that all native scrollbars on the page have the same
* height.
*
* @return the height in pixels
*/
public static int getNativeScrollbarHeight() {
maybeRecalculateNativeScrollbarSize();
return nativeHeight;
}
/**
* Get the width of a native vertical scrollbar.
*
* <p>
* This method assumes that all native vertical scrollbars on the page have
* the same width.
*
* @return the height in pixels
*/
public static int getNativeScrollbarWidth() {
maybeRecalculateNativeScrollbarSize();
return nativeWidth;
}
/**
* Check whether or not the native vertical scrollbar is aligned on the left
* side of the scrollable element in RTL mode.
*
* @return true if left aligned, false if not
*/
public static boolean isScrollbarLeftAlignedInRtl() {
maybeRecalculateNativeScrollbarSize();
return nativeRtl;
}
/**
* Recalculate the height and width of a native scrollbar.
*/
private static void maybeRecalculateNativeScrollbarSize() {
// Check if the size has already been calculated.
if (nativeHeight > -1) {
return;
}
// Create a scrollable element and attach it to the body.
Element scrollable = Document.get().createDivElement();
scrollable.getStyle().setPosition(Position.ABSOLUTE);
scrollable.getStyle().setTop(0.0, Unit.PX);
scrollable.getStyle().setLeft(0.0, Unit.PX);
scrollable.getStyle().setHeight(100.0, Unit.PX);
scrollable.getStyle().setWidth(100.0, Unit.PX);
scrollable.getStyle().setOverflow(Overflow.SCROLL);
scrollable.getStyle().setVisibility(Visibility.HIDDEN);
scrollable.getStyle().setProperty("direction", "rtl");
Document.get().getBody().appendChild(scrollable);
// Add some content.
Element content = Document.get().createDivElement();
content.setInnerText("content");
scrollable.appendChild(content);
// Measure the height and width.
nativeHeight = scrollable.getOffsetHeight() - scrollable.getClientHeight();
nativeWidth = scrollable.getOffsetWidth() - scrollable.getClientWidth();
nativeRtl = (content.getAbsoluteLeft() > scrollable.getAbsoluteLeft());
// Detach the scrollable element.
scrollable.removeFromParent();
}
public HandlerRegistration addScrollHandler(ScrollHandler handler) {
// Sink the event on the scrollable element, not the root element.
Event.sinkEvents(getScrollableElement(), Event.ONSCROLL);
return addHandler(handler, ScrollEvent.getType());
}
/**
* Get the scrollable element.
*
* @return the scrollable element
*/
protected abstract Element getScrollableElement();
@Override
protected void onAttach() {
super.onAttach();
/*
* Attach the event listener in onAttach instead of onLoad so users cannot
* accidentally override it.
*/
Event.setEventListener(getScrollableElement(), this);
}
@Override
protected void onDetach() {
/*
* Detach the event listener in onDetach instead of onUnload so users cannot
* accidentally override it.
*/
Event.setEventListener(getScrollableElement(), null);
super.onDetach();
}
}