All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gwt.material.design.client.base.helper.ScrollHelper Maven / Gradle / Ivy

/*
 * #%L
 * GwtMaterial
 * %%
 * Copyright (C) 2015 - 2018 GwtMaterialDesign
 * %%
 * 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.
 * #L%
 */
package gwt.material.design.client.base.helper;

import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.ui.Widget;
import gwt.material.design.client.constants.OffsetPosition;
import gwt.material.design.client.js.ScrollOption;
import gwt.material.design.jquery.client.api.Functions;
import gwt.material.design.jquery.client.api.JQueryElement;

import static gwt.material.design.jquery.client.api.JQuery.$;

/**
 * A set of scroll helper utils for GMD Widgets
 *
 * @author [email protected]
 */
public class ScrollHelper {

    private OffsetPosition offsetPosition = OffsetPosition.TOP;
    private Element containerElement;
    private Functions.Func completeCallback;
    private String easing = "swing";
    private int addedScrollOffset;
    private int duration = 400;
    private double offset;

    public ScrollHelper() {
        containerElement = getDefaultContainer();
    }

    public Functions.Func getCompleteCallback() {
        return completeCallback;
    }

    /**
     * A function to call once the scrolling is complete, called once per matched element.
     */
    public void setCompleteCallback(Functions.Func completeCallback) {
        this.completeCallback = completeCallback;
    }

    public String getEasing() {
        return easing;
    }

    /**
     * An easing function specifies the speed at which the animation progresses at different points within the animation.
     * The only easing implementations in the jQuery library are the default, called swing, and one that progresses at a
     * constant pace, called linear.
     */
    public void setEasing(String easing) {
        this.easing = easing;
    }

    public double getOffset() {
        return offset;
    }

    public int getDuration() {
        return duration;
    }

    /**
     * Determines how long the animation will run in milliseconds.
     */
    public void setDuration(int duration) {
        this.duration = duration;
    }

    /**
     * Will scroll target widget.
     */
    public void scrollTo(Widget widget) {
        scrollTo(widget.getElement());
    }

    /**
     * Will scroll to target element.
     */
    public void scrollTo(Element target) {
        scrollTo(extractOffsetPosition(target));
    }

    /**
     * Will scroll to target offset.
     */
    public void scrollTo(double offset) {
        this.offset = offset;

        ScrollOption option = new ScrollOption();
        JQueryElement target = getContainerElement();
        if (containerElement != getDefaultContainer()) {
            offset = target.scrollTop() - target.offset().top + offset;
        } else {
            target = $("html, body");
        }
        option.scrollTop = offset - addedScrollOffset;

        target.animate(option, duration, easing, () -> {
            if (completeCallback != null) {
                completeCallback.call();
            }
        });
    }

    /**
     * Will detect if {@link #containerElement} has horizontal scrollbar.
     */
    public boolean hasHorizontalScrollbar() {
        return containerElement.getScrollWidth() > containerElement.getClientWidth();
    }

    /**
     * Will detect if {@link #containerElement} has vertical scrollbar.
     */
    public boolean hasVerticalScrollbar() {
        return containerElement.getScrollHeight() > containerElement.getClientHeight();
    }

    /**
     * Will recalculate the offset provided by the positioning based on the container's height
     * See {@link #setOffsetPosition(OffsetPosition)}
     */
    public double extractOffsetPosition(Element target) {
        double offsetTop = $(target).offset().top;
        double containerHeight = $(containerElement).height();
        switch (getOffsetPosition()) {
            case MIDDLE:
                offsetTop = offsetTop - (containerHeight / 2) + ($(target).height() / 2);
                break;
            case BOTTOM:
                offsetTop = (offsetTop - containerHeight) + $(target).height();
                break;
        }

        return offsetTop;
    }

    /**
     * Will perform a detection whether the widget is in the View Port Scope or not, providing
     * the {@link #containerElement} as the wrapper or container of the target element.
     * 

* Note: By default if you didn't provide a container, the html or body element should be * applied as the target's container. * * @param widget The widget you are checking if it's inside the viewport scope. */ public boolean isInViewPort(Widget widget) { return isInViewPort(widget.getElement()); } public boolean isInViewPort(Widget widget, double addedHeight) { return isInViewPort(widget.getElement(), addedHeight); } /** * Will perform a detection whether the element is in the View Port Scope or not, providing * the {@link #containerElement} as the wrapper or container of the target element. *

* Note: By default if you didn't provide a container, the html or body element should be * applied as the target's container. * * @param element The element you are checking if it's inside the viewport scope. */ public boolean isInViewPort(Element element) { return isInViewPort(element, 0); } public boolean isInViewPort(Element element, double addedHeight) { double elementTop = getElementTop(element) + addedHeight; double elementBottom = elementTop + $(element).outerHeight() + addedHeight; JQueryElement target = getContainerElement(); double viewportTop = target.scrollTop(); if (target.asElement() != getDefaultContainer()) { viewportTop = getElementTop(target.asElement()); } double viewportBottom = viewportTop + target.height(); return elementBottom > viewportTop && elementTop < viewportBottom; } //TODO: Convert to JSInterop protected native double getElementTop(Element element) /*-{ var rectObject = element.getBoundingClientRect(); return rectObject.top; }-*/; protected Element getDefaultContainer() { return $("html, body").asElement(); } /** * The container element of which the scrolling feature will be applied. */ public void setContainerElement(Element containerElement) { this.containerElement = containerElement; } /** * The container of which the scrolling feature will be applied. */ public void setContainer(Widget widget) { this.containerElement = widget.getElement(); } public int getAddedScrollOffset() { return addedScrollOffset; } /** * Additional offset height in pixels to be added on overall scroll offset once called {@link #scrollTo(double)} */ public void setAddedScrollOffset(int addedScrollOffset) { this.addedScrollOffset = addedScrollOffset; } public JQueryElement getContainerElement() { if (containerElement == null) { return $("html, body"); } return $(containerElement); } public OffsetPosition getOffsetPosition() { return offsetPosition; } /** * Will set the desired offset position of the target element. * Available options are TOP, MIDDLE and BOTTOM. */ public void setOffsetPosition(OffsetPosition offsetPosition) { this.offsetPosition = offsetPosition; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy