Java tutorial
package com.cgxlib.core.component.affix; /* * #%L * CGXlib * %% * Copyright (C) 2016 CGXlib (http://www.cgxlib.com) * %% * 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% */ import com.cgxlib.core.*; import com.cgxlib.xq.client.Function; import com.cgxlib.xq.client.XQ; import com.cgxlib.xq.client.js.JsUtils; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.user.client.Timer; import java.util.ArrayList; import java.util.List; /** * */ public class Affix extends CGXComponentBase<AffixView.ViewHandler> { public static final Class<Affix> CGX = CGXlib.registerPlugin(Affix.class, new CGXPlugin<Affix, AffixView.ViewHandler>() { @Override public List<HTML5DataAPILoader> autoLoaders() { HTML5DataAPILoader selector = GWT.create(AffixHTML5Loader.class); List<HTML5DataAPILoader> selectors = new ArrayList<HTML5DataAPILoader>(); selectors.add(selector); return selectors; } @Override public Affix init(CGXComponentBase xq, ViewHandlerFactory<? extends AffixView.ViewHandler> factory) { return createOrGetData(xq, factory.make()); } @Override public Affix init(XQ xq) { return createOrGetData(xq, null); } }); protected AffixOptions options; protected XQ $target; protected AffixOffset offset; protected AffixedState affixed = AffixedState.initializing; protected Integer unpin; protected Integer pinnedOffset; protected AffixView.ViewHandler viewHandler; protected Affix(XQ xq) { this(xq, new AffixBSViewHandler()); } protected Affix(XQ xq, AffixView.ViewHandler viewHandler) { super(xq, viewHandler); } protected static Affix createOrGetData(XQ xq, AffixView.ViewHandler viewHandler) { String name = "cgx.affix"; Affix comp = xq.data(name); if (comp == null) { if (viewHandler == null) { comp = new Affix(xq); } else { comp = new Affix(xq, viewHandler); } xq.data(name, comp); } return comp; } @Override protected void apply(XQ xq, AffixView.ViewHandler viewHandler) { viewHandler.init(this); this.viewHandler = viewHandler; } public Affix affix() { return affix(new AffixOptions()); } public Affix affix(AffixOptions affixOptions) { options = affixOptions; offset = affixOptions.offset(); if (offset == null) { offset = new AffixOffset(); } String targetStr = this.attr("data-target"); if (targetStr != null && targetStr.length() > 0) { options.target($(targetStr)); } $target = options.target(); $target.on("scroll.cgx.affix.data-api", new Function() { @Override public void f() { Affix.this.affixCheckPosition(); } }); $target.on("click.cgx.affix.data-api", new Function() { @Override public void f() { Affix.this.checkPositionWithEventLoop(); } }); String offsetTopStr = this.attr("data-offset-top"); String offsetBottomStr = this.attr("data-offset-bottom"); String offsetStr = this.attr("data-offset"); try { if (offsetStr != null && offsetStr.length() > 0) { int offsetInt = Integer.parseInt(offsetBottomStr); offset.bottom(offsetInt); offset.top(offsetInt); } if (offsetBottomStr != null && offsetBottomStr.length() > 0) { offset.bottom(Integer.parseInt(offsetBottomStr)); } if (offsetTopStr != null && offsetTopStr.length() > 0) { offset.top(Integer.parseInt(offsetTopStr)); } } catch (Exception ex) { } affixCheckPosition(); return this; } public Affix affixCheckPosition() { if (!viewHandler.isVisible()) { return this; } int height = viewHandler.height(); int scrollHeight = viewHandler.scrollHeight(); Integer offsetTop = offset.top(); Integer offsetBottom = offset.bottom(); AffixedState affix = getState(scrollHeight, height, offsetTop, offsetBottom); if (affixed != affix) { if (unpin != null) { viewHandler.clearTop(); } boolean include = affix != null && affix != AffixedState.initializing; String affixType = "affix" + (include ? "-" + affix.name() : ""); NativeEvent e = CGXHelper.createNativeEvent(affixType, "cgx.affix"); this.trigger(e); if (JsUtils.isDefaultPrevented(e)) { return this; } affixed = affix; unpin = affix == AffixedState.bottom ? getPinnedOffset() : null; viewHandler.affixReset(); viewHandler.affixSetType(affixType); this.trigger(affixType.replace("affix", "affixed") + ".cgx.affix"); } if (affix == AffixedState.bottom) { this.offset().top = scrollHeight - height - offsetBottom; } return this; } protected AffixedState getState(Integer scrollHeight, Integer height, Integer offsetTop, Integer offsetBottom) { int scrollTop = this.$target.scrollTop(); Offset position = this.offset(); int targetHeight = this.$target.height(); if (offsetTop != null && this.affixed == AffixedState.top) { return scrollTop < offsetTop ? AffixedState.top : null; } if (this.affixed == AffixedState.bottom) { if (offsetTop != null) { return (scrollTop + this.unpin <= position.top) ? null : AffixedState.bottom; } return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? null : AffixedState.bottom; } boolean initializing = this.affixed == AffixedState.initializing; int colliderTop = initializing ? scrollTop : position.top; int colliderHeight = initializing ? targetHeight : height; if (offsetTop != null && scrollTop <= offsetTop) { return AffixedState.top; } if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) { return AffixedState.bottom; } return null; } protected void checkPositionWithEventLoop() { Timer timer = new Timer() { @Override public void run() { affixCheckPosition(); } }; timer.schedule(1); } protected Integer getPinnedOffset() { if (pinnedOffset != null) { return pinnedOffset; } viewHandler.affixReset(); viewHandler.affixSet(); int scrollTop = viewHandler.targetScrollTop($target); Offset position = this.offset(); pinnedOffset = position.top - scrollTop; return pinnedOffset; } protected enum AffixedState { initializing, top, bottom; } }