diff --git a/ionic/components/item/item-group.ts b/ionic/components/item/item-group.ts
index c3b8e80244..83abbd93c6 100644
--- a/ionic/components/item/item-group.ts
+++ b/ionic/components/item/item-group.ts
@@ -1,4 +1,8 @@
-import {Directive, ElementRef} from 'angular2/angular2';
+import {Directive, ElementRef, Host, Optional} from 'angular2/angular2';
+import {Content} from '../content/content';
+import {throttle} from '../../util/util';
+import {position, offset, CSS} from '../../util/dom';
+import {IonicConfig} from '../../config/config';
/**
* TODO
@@ -34,8 +38,126 @@ export class ItemGroupTitle {
* TODO
* @param {ElementRef} elementRef TODO
*/
- constructor(elementRef: ElementRef) {
+ constructor(elementRef: ElementRef, config: IonicConfig, @Host() content: Content) {
this.isSticky = true;
+ this.content = content;
this.ele = elementRef.nativeElement;
+ this.parent = this.ele.parentNode;
+ }
+
+ onInit() {
+
+ this.scrollContent = this.content.elementRef.nativeElement.children[0];
+
+ this.scrollMin = 0;
+ this.scrollMax = 0;
+ this.scrollTransition = 0;
+ this.isSticking = false;
+
+
+ this.scrollContent.addEventListener('scroll', event => this.scrollEvent(event));
+
+ this.calculateScrollLimits = scrollTop => {
+ var containerPosition = position(this.parent);
+ var elementOffset = offset(this.ele);
+
+ var containerTop = containerPosition.top;
+ var containerHeight = containerPosition.height;
+
+ var affixHeight = elementOffset.height;
+
+ this.scrollMin = containerTop;
+ this.scrollMax = this.scrollMin + containerHeight;
+ this.scrollTransition = this.scrollMax - affixHeight;
+ };
+
+ // throttled version of the same calculation
+ let CALCULATION_THROTTLE_MS = 500;
+ this.throttledCalculateScrollLimits = throttle(
+ this.calculateScrollLimits,
+ CALCULATION_THROTTLE_MS,
+ {trailing: false}
+ );
+ }
+
+ applyTransform(element, transformString) {
+ // do not apply the transformation if it is already applied
+ if (element.style[CSS.transform] == transformString) {
+ }
+ else {
+ element.style[CSS.transform] = transformString;
+ }
+ }
+
+ translateUp(element, dy, executeImmediately) {
+ var translateDyPixelsUp = dy == 0 ? 'translate3d(0px, 0px, 0px)' : 'translate3d(0px, -' + dy + 'px, 0px)';
+ // if immediate execution is requested, then just execute immediately
+ // if not, execute in the animation frame.
+ if (executeImmediately) {
+ this.applyTransform(element, translateDyPixelsUp);
+ }
+ else {
+ // see http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
+ // see http://ionicframework.com/docs/api/utility/ionic.DomUtil/
+ requestAnimationFrame( a => this.applyTransform(element, translateDyPixelsUp) );
+ }
+ }
+
+ createAffixClone() {
+ var clone = this.ele.cloneNode(true);
+ clone.style.position = 'absolute';
+ clone.style.top = 0;
+ clone.style.left = 0;
+ clone.style.right = 0;
+
+ this.scrollContent.parentNode.appendChild(clone);
+ return clone;
+ }
+
+ scrollEvent(event) {
+ var scrollTop = event.target.scrollTop;
+
+ // when scroll to top, we should always execute the immediate calculation.
+ // this is because of some weird problem which is hard to describe.
+ // if you want to experiment, always use the throttled one and just click on the page
+ // you will see all affix elements stacked on top
+ if (scrollTop == 0) {
+ this.calculateScrollLimits(scrollTop);
+ }
+ else {
+ this.throttledCalculateScrollLimits(scrollTop);
+ }
+
+ // when we scrolled to the container, create the clone of element and place it on top
+ if (scrollTop >= this.scrollMin && scrollTop <= this.scrollMax) {
+ // we need to track if we created the clone just now
+ // that is important since normally we apply the transforms in the animation frame
+ // but, we need to apply the transform immediately when we add the element for the first time. otherwise it is too late!
+ var cloneCreatedJustNow = false;
+
+ if (!this.affixClone) {
+ this.affixClone = this.createAffixClone();
+ cloneCreatedJustNow = true;
+ this.isSticking = true;
+ }
+
+ // if we're reaching towards the end of the container, apply some nice translation to move up/down the clone
+ // but if we're reached already to the container and we're far away than the end, move clone to top
+ if (scrollTop > this.scrollTransition) {
+ this.translateUp(this.affixClone, Math.floor(scrollTop - this.scrollTransition), cloneCreatedJustNow);
+ } else {
+ this.translateUp(this.affixClone, 0, cloneCreatedJustNow);
+ }
+ } else {
+ this.removeAffixClone();
+ this.isSticking = false;
+ }
+ }
+
+ removeAffixClone() {
+ if (this.affixClone) {
+ this.scrollContent.parentNode.removeChild(this.affixClone);
+ this.affixClone = null;
+ }
}
}
diff --git a/ionic/components/item/modes/ios.scss b/ionic/components/item/modes/ios.scss
index 1c102a7e4d..357731011e 100644
--- a/ionic/components/item/modes/ios.scss
+++ b/ionic/components/item/modes/ios.scss
@@ -26,14 +26,16 @@ $item-ios-divider-bg: #f5f5f5 !default;
$item-ios-divider-color: #222 !default;
$item-ios-divider-padding: 5px 15px !default;
+.item-group-title {
+ padding: $item-ios-padding-top $item-ios-padding-right $item-ios-padding-bottom $item-ios-padding-left;
+ background-color: $item-ios-divider-bg;
+ color: $item-ios-divider-color;
+}
+
.list {
- .item-group-title {
- padding: $item-ios-padding-top $item-ios-padding-right $item-ios-padding-bottom $item-ios-padding-left;
- background-color: $item-ios-divider-bg;
- color: $item-ios-divider-color;
- }
+
.item-group {
// Make sure the first and last items don't have borders
> .item:first-of-type:before {
diff --git a/ionic/components/list/test/infinite/main.html b/ionic/components/list/test/infinite/main.html
index f7ce1dc08b..d6f233e191 100644
--- a/ionic/components/list/test/infinite/main.html
+++ b/ionic/components/list/test/infinite/main.html
@@ -1,15 +1,10 @@
+
-
+
+
+ {{item.title}}
+
+
+
-
-
-
-
- {{item.title}}
-
-
-
-
-
-
-
+
diff --git a/ionic/components/scroll/test/basic/main.html b/ionic/components/scroll/test/basic/main.html
index 849a3fa850..3637a85aae 100644
--- a/ionic/components/scroll/test/basic/main.html
+++ b/ionic/components/scroll/test/basic/main.html
@@ -1,4 +1,4 @@
-
+
Scroll
@@ -20,7 +20,7 @@
-
+