UNPKG

ionic-framework

Version:

The ionic-framework package comes with both Javascript and Sass frontend dependencies, located in the root of the package, and a Node API, located in `tooling/`.

431 lines (429 loc) 15.6 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var core_1 = require('angular2/core'); var common_1 = require('angular2/common'); var content_1 = require('../content/content'); var icon_1 = require('../icon/icon'); var util_1 = require('../../util/util'); var dom_1 = require('../../util/dom'); /** * @name Refresher * @description * Allows you to add pull-to-refresh to an Content component. * Place it as the first child of your Content or Scroll element. * * When refreshing is complete, call `refresher.complete()` from your controller. * * @usage * ```html * <ion-content> * <ion-refresher (starting)="doStarting()" * (refresh)="doRefresh($event, refresher)" * (pulling)="doPulling($event, amt)"> * </ion-refresher> * * </ion-content> * ``` * * ```ts * export class MyClass { * constructor(){} * doRefresh(refresher) { * console.log('Refreshing!', refresher); * * setTimeout(() => { * console.log('Pull to refresh complete!', refresher); * refresher.complete(); * }) * } * * doStarting() { * console.log('Pull started!'); * } * * doPulling(amt) { * console.log('You have pulled', amt); * } * } * ``` * @demo /docs/v2/demos/refresher/ * * @property {string} [pullingIcon] - the icon you want to display when you begin to pull down * @property {string} [pullingText] - the text you want to display when you begin to pull down * @property {string} [refreshingIcon] - the icon you want to display when performing a refresh * @property {string} [refreshingText] - the text you want to display when performing a refresh * * @property {any} (refresh) - the methond on your class you want to perform when you refreshing * @property {any} (starting) - the methond on your class you want to perform when you start pulling down * @property {any} (pulling) - the methond on your class you want to perform when you are pulling down * */ var Refresher = (function () { function Refresher(content, element) { this.content = content; this.isDragging = false; this.isOverscrolling = false; this.dragOffset = 0; this.lastOverscroll = 0; this.ptrThreshold = 0; this.activated = false; this.scrollTime = 500; this.canOverscroll = false; this.pulling = new core_1.EventEmitter(); this.refresh = new core_1.EventEmitter(); this.starting = new core_1.EventEmitter(); this.ele = element.nativeElement; this.ele.classList.add('content'); } /** * @private */ Refresher.prototype.ngOnInit = function () { var sp = this.content.getNativeElement(); var sc = this.content.scrollElement; this.startY = null; this.deltaY = null; this.scrollHost = sp; this.scrollChild = sc; util_1.defaults(this, { pullingIcon: 'md-arrow-down', refreshingIcon: 'ionic' }); this.showSpinner = !util_1.isDefined(this.refreshingIcon) && this.spinner != 'none'; this.showIcon = util_1.isDefined(this.refreshingIcon); this._touchMoveListener = this._handleTouchMove.bind(this); this._touchEndListener = this._handleTouchEnd.bind(this); this._handleScrollListener = this._handleScroll.bind(this); sc.addEventListener('touchmove', this._touchMoveListener); sc.addEventListener('touchend', this._touchEndListener); sc.addEventListener('scroll', this._handleScrollListener); }; /** * @private */ Refresher.prototype.ngOnDestroy = function () { var sc = this.content.scrollElement; sc.removeEventListener('touchmove', this._touchMoveListener); sc.removeEventListener('touchend', this._touchEndListener); sc.removeEventListener('scroll', this._handleScrollListener); }; /** * @private * @param {TODO} val TODO */ Refresher.prototype.overscroll = function (val) { this.scrollChild.style[dom_1.CSS.transform] = 'translateY(' + val + 'px)'; this.lastOverscroll = val; }; /** * @private * @param {TODO} target TODO * @param {TODO} newScrollTop TODO */ Refresher.prototype.nativescroll = function (target, newScrollTop) { // creates a scroll event that bubbles, can be cancelled, and with its view // and detail property initialized to window and 1, respectively target.scrollTop = newScrollTop; var e = document.createEvent("UIEvents"); e.initUIEvent("scroll", true, true, window, 1); target.dispatchEvent(e); }; /** * @private * @param {TODO} enabled TODO */ Refresher.prototype.setScrollLock = function (enabled) { var _this = this; // set the scrollbar to be position:fixed in preparation to overscroll // or remove it so the app can be natively scrolled if (enabled) { dom_1.raf(function () { _this.scrollChild.classList.add('overscroll'); _this.show(); }); } else { dom_1.raf(function () { _this.scrollChild.classList.remove('overscroll'); _this.hide(); _this.deactivate(); }); } }; /** * @private */ Refresher.prototype.activate = function () { //this.ele.classList.add('active'); this.isActive = true; //this.starting.next(); }; /** * @private */ Refresher.prototype.deactivate = function () { var _this = this; // give tail 150ms to finish setTimeout(function () { _this.isActive = false; _this.isRefreshing = false; _this.isRefreshingTail = false; // deactivateCallback if (_this.activated) _this.activated = false; }, 150); }; /** * @private */ Refresher.prototype.start = function () { // startCallback this.isRefreshing = true; this.refresh.next(this); //$scope.$onRefresh(); }; /** * @private */ Refresher.prototype.show = function () { // showCallback this.ele.classList.remove('invisible'); }; /** * @private */ Refresher.prototype.hide = function () { // showCallback this.ele.classList.add('invisible'); }; /** * @private */ Refresher.prototype.tail = function () { // tailCallback this.ele.classList.add('refreshing-tail'); }; /** * @private */ Refresher.prototype.complete = function () { var _this = this; setTimeout(function () { dom_1.raf(_this.tail.bind(_this)); // scroll back to home during tail animation _this.scrollTo(0, _this.scrollTime, _this.deactivate.bind(_this)); // return to native scrolling after tail animation has time to finish setTimeout(function () { if (_this.isOverscrolling) { _this.isOverscrolling = false; _this.setScrollLock(false); } }, _this.scrollTime); }, this.scrollTime); }; /** * @private * @param {TODO} Y TODO * @param {TODO} duration TODO * @param {Function} callback TODO */ Refresher.prototype.scrollTo = function (Y, duration, callback) { // scroll animation loop w/ easing // credit https://gist.github.com/dezinezync/5487119 var start = Date.now(), from = this.lastOverscroll; if (from === Y) { callback && callback(); return; /* Prevent scrolling to the Y point if already there */ } // decelerating to zero velocity function easeOutCubic(t) { return (--t) * t * t + 1; } // scroll loop function scroll() { var currentTime = Date.now(), time = Math.min(1, ((currentTime - start) / duration)), // where .5 would be 50% of time on a linear scale easedT gives a // fraction based on the easing method easedT = easeOutCubic(time); this.overscroll(Math.round((easedT * (Y - from)) + from)); if (time < 1) { dom_1.raf(scroll.bind(this)); } else { if (Y < 5 && Y > -5) { this.isOverscrolling = false; this.setScrollLock(false); } callback && callback(); } } // start scroll loop dom_1.raf(scroll.bind(this)); }; /** * @private * TODO * @param {Event} e TODO */ Refresher.prototype._handleTouchMove = function (e) { //console.log('TOUCHMOVE', e); // if multitouch or regular scroll event, get out immediately if (!this.canOverscroll || e.touches.length > 1) { return; } //if this is a new drag, keep track of where we start if (this.startY === null) { this.startY = parseInt(e.touches[0].screenY, 10); } // how far have we dragged so far? this.deltaY = parseInt(e.touches[0].screenY, 10) - this.startY; // if we've dragged up and back down in to native scroll territory if (this.deltaY - this.dragOffset <= 0 || this.scrollHost.scrollTop !== 0) { if (this.isOverscrolling) { this.isOverscrolling = false; this.setScrollLock(false); } if (this.isDragging) { this.nativescroll(this.scrollHost, Math.round(this.deltaY - this.dragOffset) * -1); } // if we're not at overscroll 0 yet, 0 out if (this.lastOverscroll !== 0) { this.overscroll(0); } return; } else if (this.deltaY > 0 && this.scrollHost.scrollTop === 0 && !this.isOverscrolling) { // starting overscroll, but drag started below scrollTop 0, so we need to offset the position this.dragOffset = this.deltaY; } // prevent native scroll events while overscrolling e.preventDefault(); // if not overscrolling yet, initiate overscrolling if (!this.isOverscrolling) { this.isOverscrolling = true; this.setScrollLock(true); } this.isDragging = true; // overscroll according to the user's drag so far this.overscroll(Math.round((this.deltaY - this.dragOffset) / 3)); // Pass an incremental pull amount to the EventEmitter this.pulling.next(this.lastOverscroll); // update the icon accordingly if (!this.activated && this.lastOverscroll > this.ptrThreshold) { this.activated = true; dom_1.raf(this.activate.bind(this)); } else if (this.activated && this.lastOverscroll < this.ptrThreshold) { this.activated = false; dom_1.raf(this.deactivate.bind(this)); } }; /** * @private * TODO * @param {Event} e TODO */ Refresher.prototype._handleTouchEnd = function (e) { void 0; // if this wasn't an overscroll, get out immediately if (!this.canOverscroll && !this.isDragging) { return; } // reset Y this.startY = null; // the user has overscrolled but went back to native scrolling if (!this.isDragging) { this.dragOffset = 0; this.isOverscrolling = false; this.setScrollLock(false); } else { this.isDragging = false; this.dragOffset = 0; // the user has scroll far enough to trigger a refresh if (this.lastOverscroll > this.ptrThreshold) { this.start(); this.scrollTo(this.ptrThreshold, this.scrollTime); } else { this.scrollTo(0, this.scrollTime, this.deactivate.bind(this)); this.isOverscrolling = false; } } }; /** * @private * TODO * @param {Event} e TODO */ Refresher.prototype._handleScroll = function (e) { void 0; }; __decorate([ core_1.Input(), __metadata('design:type', String) ], Refresher.prototype, "pullingIcon", void 0); __decorate([ core_1.Input(), __metadata('design:type', String) ], Refresher.prototype, "pullingText", void 0); __decorate([ core_1.Input(), __metadata('design:type', String) ], Refresher.prototype, "refreshingIcon", void 0); __decorate([ core_1.Input(), __metadata('design:type', String) ], Refresher.prototype, "refreshingText", void 0); __decorate([ core_1.Input(), __metadata('design:type', String) ], Refresher.prototype, "spinner", void 0); __decorate([ core_1.Output(), __metadata('design:type', core_1.EventEmitter) ], Refresher.prototype, "pulling", void 0); __decorate([ core_1.Output(), __metadata('design:type', core_1.EventEmitter) ], Refresher.prototype, "refresh", void 0); __decorate([ core_1.Output(), __metadata('design:type', core_1.EventEmitter) ], Refresher.prototype, "starting", void 0); Refresher = __decorate([ core_1.Component({ selector: 'ion-refresher', host: { '[class.active]': 'isActive', '[class.refreshing]': 'isRefreshing', '[class.refreshingTail]': 'isRefreshingTail' }, template: '<div class="refresher-content" [class.refresher-with-text]="pullingText || refreshingText">' + '<div class="icon-pulling">' + '<ion-icon [name]="pullingIcon"></ion-icon>' + '</div>' + '<div class="text-pulling" [innerHTML]="pullingText" *ngIf="pullingText"></div>' + '<div class="icon-refreshing">' + '<ion-icon [name]="refreshingIcon"></ion-icon>' + '</div>' + '<div class="text-refreshing" [innerHTML]="refreshingText" *ngIf="refreshingText"></div>' + '</div>', directives: [common_1.NgIf, common_1.NgClass, icon_1.Icon] }), __param(0, core_1.Host()), __metadata('design:paramtypes', [content_1.Content, core_1.ElementRef]) ], Refresher); return Refresher; })(); exports.Refresher = Refresher;