mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 11:17:19 +08:00
refactor(item-sliding)
This commit is contained in:
187
ionic/components/item/item-sliding-gesture.ts
Normal file
187
ionic/components/item/item-sliding-gesture.ts
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
import {Hammer} from 'ionic/gestures/hammer';
|
||||||
|
import {DragGesture} from 'ionic/gestures/drag-gesture';
|
||||||
|
import {List} from '../list/list';
|
||||||
|
|
||||||
|
import * as util from 'ionic/util';
|
||||||
|
import {CSS, raf, closest} from 'ionic/util/dom';
|
||||||
|
|
||||||
|
|
||||||
|
export class ItemSlidingGesture extends DragGesture {
|
||||||
|
constructor(list: List, listEle) {
|
||||||
|
super(listEle, {
|
||||||
|
direction: 'x',
|
||||||
|
threshold: list.width()
|
||||||
|
});
|
||||||
|
|
||||||
|
this.data = {};
|
||||||
|
this.openItems = 0;
|
||||||
|
|
||||||
|
this.list = list;
|
||||||
|
this.listEle = listEle;
|
||||||
|
this.canDrag = true;
|
||||||
|
this.listen();
|
||||||
|
|
||||||
|
this.on('tap', ev => {
|
||||||
|
if (!isFromOptionButtons(ev.target)) {
|
||||||
|
let didClose = this.closeOpened();
|
||||||
|
if (didClose) {
|
||||||
|
ev.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onDragStart(ev) {
|
||||||
|
let itemContainerEle = getItemConatiner(ev.target);
|
||||||
|
if (!itemContainerEle) return;
|
||||||
|
|
||||||
|
this.closeOpened(ev, itemContainerEle);
|
||||||
|
|
||||||
|
let openAmout = this.getOpenAmount(itemContainerEle);
|
||||||
|
let itemData = this.getData(itemContainerEle);
|
||||||
|
|
||||||
|
if (openAmout) {
|
||||||
|
return ev.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
itemContainerEle.classList.add('active-slide');
|
||||||
|
|
||||||
|
this.setData(itemContainerEle, 'offsetX', openAmout);
|
||||||
|
this.setData(itemContainerEle, 'startX', ev.center[this.direction]);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDrag(ev) {
|
||||||
|
let itemContainerEle = getItemConatiner(ev.target);
|
||||||
|
if (!itemContainerEle || !isActive(itemContainerEle)) return;
|
||||||
|
|
||||||
|
let itemData = this.getData(itemContainerEle);
|
||||||
|
|
||||||
|
if (!itemData.optsWidth) {
|
||||||
|
itemData.optsWidth = getOptionsWidth(itemContainerEle);
|
||||||
|
if (!itemData.optsWidth) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = ev.center[this.direction];
|
||||||
|
let delta = x - itemData.startX;
|
||||||
|
|
||||||
|
let newX = Math.max(0, itemData.offsetX - delta);
|
||||||
|
|
||||||
|
if (newX > itemData.optsWidth) {
|
||||||
|
// Calculate the new X position, capped at the top of the buttons
|
||||||
|
newX = -Math.min(-itemData.optsWidth, -itemData.optsWidth + (((delta + itemData.optsWidth) * 0.4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.open(itemContainerEle, newX, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDragEnd(ev) {
|
||||||
|
let itemContainerEle = getItemConatiner(ev.target);
|
||||||
|
if (!itemContainerEle || !isActive(itemContainerEle)) return;
|
||||||
|
|
||||||
|
// If we are currently dragging, we want to snap back into place
|
||||||
|
// The final resting point X will be the width of the exposed buttons
|
||||||
|
let itemData = this.getData(itemContainerEle);
|
||||||
|
|
||||||
|
var restingPoint = itemData.optsWidth;
|
||||||
|
|
||||||
|
// Check if the drag didn't clear the buttons mid-point
|
||||||
|
// and we aren't moving fast enough to swipe open
|
||||||
|
|
||||||
|
if (this.getOpenAmount(itemContainerEle) < (restingPoint / 2)) {
|
||||||
|
|
||||||
|
// If we are going left but too slow, or going right, go back to resting
|
||||||
|
if (ev.direction & Hammer.DIRECTION_RIGHT) {
|
||||||
|
// Left
|
||||||
|
restingPoint = 0;
|
||||||
|
|
||||||
|
} else if (Math.abs(ev.velocityX) < 0.3) {
|
||||||
|
// Right
|
||||||
|
restingPoint = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setData(itemContainerEle, 'opened', restingPoint > 0);
|
||||||
|
|
||||||
|
raf(() => {
|
||||||
|
this.open(itemContainerEle, restingPoint, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
closeOpened(ev, doNotCloseEle) {
|
||||||
|
let didClose = false;
|
||||||
|
if (this.openItems) {
|
||||||
|
let openItemElements = this.listEle.querySelectorAll('.active-slide');
|
||||||
|
for (let i = 0; i < openItemElements.length; i++) {
|
||||||
|
if (openItemElements[i] !== doNotCloseEle) {
|
||||||
|
this.open(openItemElements[i], 0, true);
|
||||||
|
didClose = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return didClose;
|
||||||
|
}
|
||||||
|
|
||||||
|
open(itemContainerEle, openAmount, animate) {
|
||||||
|
let slidingEle = itemContainerEle.querySelector('ion-item');
|
||||||
|
if (!slidingEle) return;
|
||||||
|
|
||||||
|
this.setData(itemContainerEle, 'openAmount', openAmount);
|
||||||
|
|
||||||
|
clearTimeout(this.getData(itemContainerEle).timerId);
|
||||||
|
|
||||||
|
if (openAmount > 0) {
|
||||||
|
this.openItems++;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
let timerId = setTimeout(() => {
|
||||||
|
if (slidingEle.style[CSS.transform] === '') {
|
||||||
|
itemContainerEle.classList.remove('active-slide');
|
||||||
|
this.openItems--;
|
||||||
|
}
|
||||||
|
}, 400);
|
||||||
|
this.setData(itemContainerEle, 'timerId', timerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
slidingEle.style[CSS.transform] = (openAmount === 0 ? '' : 'translate3d(' + -openAmount + 'px,0,0)');
|
||||||
|
slidingEle.style[CSS.transition] = (animate ? '' : 'none');
|
||||||
|
}
|
||||||
|
|
||||||
|
getOpenAmount(itemContainerEle) {
|
||||||
|
return this.getData(itemContainerEle).openAmount || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getData(itemContainerEle) {
|
||||||
|
return this.data[itemContainerEle && itemContainerEle.$ionSlide] || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
setData(itemContainerEle, key, value) {
|
||||||
|
if (!this.data[itemContainerEle.$ionSlide]) {
|
||||||
|
this.data[itemContainerEle.$ionSlide] = {};
|
||||||
|
}
|
||||||
|
this.data[itemContainerEle.$ionSlide][key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlisten() {
|
||||||
|
super.unlisten();
|
||||||
|
this.listEle = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getItemConatiner(ele) {
|
||||||
|
return closest(ele, 'ion-item-sliding', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFromOptionButtons(ele) {
|
||||||
|
return !!closest(ele, 'ion-item-options', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOptionsWidth(itemContainerEle) {
|
||||||
|
let optsEle = itemContainerEle.querySelector('ion-item-options');
|
||||||
|
if (optsEle) {
|
||||||
|
return optsEle.offsetWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isActive(itemContainerEle) {
|
||||||
|
return itemContainerEle.classList.contains('active-slide');
|
||||||
|
}
|
36
ionic/components/item/item-sliding.scss
Normal file
36
ionic/components/item/item-sliding.scss
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* The hidden right-side buttons that can be exposed under a list item
|
||||||
|
* with dragging.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ion-item-sliding {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item-options {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: $z-index-item-options;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item-sliding.active-slide {
|
||||||
|
|
||||||
|
.item {
|
||||||
|
position: relative;
|
||||||
|
z-index: $z-index-item-options + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item-options {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
@ -1,31 +1,7 @@
|
|||||||
import {Component, Directive, ElementRef, NgIf, Host, Optional, Renderer, NgZone} from 'angular2/angular2';
|
import {Component, ElementRef, Optional} from 'angular2/angular2';
|
||||||
|
|
||||||
import {Gesture} from 'ionic/gestures/gesture';
|
import {List} from '../list/list';
|
||||||
import {DragGesture} from 'ionic/gestures/drag-gesture';
|
|
||||||
import {Hammer} from 'ionic/gestures/hammer';
|
|
||||||
import {List} from 'ionic/components/list/list';
|
|
||||||
|
|
||||||
import * as util from 'ionic/util';
|
|
||||||
|
|
||||||
import {CSS, raf} from 'ionic/util/dom';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Directive({
|
|
||||||
selector: 'ion-item-options > button,ion-item-options > [button]',
|
|
||||||
host: {
|
|
||||||
'(click)': 'clicked($event)'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
export class ItemSlidingOptionButton {
|
|
||||||
constructor(elementRef: ElementRef) {
|
|
||||||
}
|
|
||||||
clicked(event) {
|
|
||||||
// Don't allow the click to propagate
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name ionItem
|
* @name ionItem
|
||||||
@ -36,238 +12,35 @@ export class ItemSlidingOptionButton {
|
|||||||
* @usage
|
* @usage
|
||||||
* ```html
|
* ```html
|
||||||
* <ion-list>
|
* <ion-list>
|
||||||
* <ion-item-sliding *ng-for="#item of items" (click)="itemTapped($event, item)">
|
* <ion-item-sliding *ng-for="#item of items">
|
||||||
|
* <ion-item (click)="itemTapped(item)">
|
||||||
* {{item.title}}
|
* {{item.title}}
|
||||||
* <div class="item-note" item-right>
|
* </ion-item>
|
||||||
* {{item.note}}
|
* <ion-item-options>
|
||||||
* </div>
|
* <button (click)="favorite(item)">Favorite</button>
|
||||||
|
* <button (click)="share(item)">Share</button>
|
||||||
|
* </ion-item-options>
|
||||||
* </ion-item>
|
* </ion-item>
|
||||||
* </ion-list>
|
* </ion-list>
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ion-item-sliding',
|
selector: 'ion-item-sliding',
|
||||||
inputs: [
|
|
||||||
'sliding'
|
|
||||||
],
|
|
||||||
template:
|
template:
|
||||||
'<ng-content select="ion-item-options"></ng-content>' +
|
'<ng-content select="ion-item"></ng-content>' +
|
||||||
'<ion-item-sliding-content>' +
|
'<ng-content select="ion-item-options"></ng-content>'
|
||||||
'<ng-content select="[item-left]"></ng-content>' +
|
|
||||||
'<ng-content select="[item-right]"></ng-content>' +
|
|
||||||
'<ion-item-content>' +
|
|
||||||
'<ng-content></ng-content>'+
|
|
||||||
'</ion-item-content>' +
|
|
||||||
'</ion-item-sliding-content>'
|
|
||||||
})
|
})
|
||||||
export class ItemSliding {
|
export class ItemSliding {
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
* @param {ElementRef} elementRef A reference to the component's DOM element.
|
|
||||||
*/
|
|
||||||
constructor(elementRef: ElementRef, renderer: Renderer, @Optional() @Host() list: List, zone: NgZone) {
|
|
||||||
this._zone = zone;
|
|
||||||
renderer.setElementClass(elementRef, 'item', true);
|
|
||||||
renderer.setElementAttribute(elementRef, 'tappable', '');
|
|
||||||
|
|
||||||
this._isOpen = false;
|
constructor(@Optional() private list: List, elementRef: ElementRef) {
|
||||||
this._isSlideActive = false;
|
list.enableSlidingItems(true);
|
||||||
this._isTransitioning = false;
|
elementRef.nativeElement.$ionSlide = ++slideIds;
|
||||||
this._transform = '';
|
|
||||||
|
|
||||||
this.list = list;
|
|
||||||
|
|
||||||
this.elementRef = elementRef;
|
|
||||||
this.swipeButtons = {};
|
|
||||||
this.optionButtons = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onInit() {
|
close() {
|
||||||
let ele = this.elementRef.nativeElement;
|
this.list.closeSlidingItems();
|
||||||
this.itemSlidingContent = ele.querySelector('ion-item-sliding-content');
|
|
||||||
this.itemOptions = ele.querySelector('ion-item-options');
|
|
||||||
this.openAmount = 0;
|
|
||||||
this._zone.runOutsideAngular(() => {
|
|
||||||
this.gesture = new ItemSlideGesture(this, this.itemSlidingContent, this._zone);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy() {
|
|
||||||
this.gesture && this.gesture.unlisten();
|
|
||||||
this.itemSlidingContent = this.itemOptionsContent = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(andStopDrag) {
|
let slideIds = 0;
|
||||||
this.openAmount = 0;
|
|
||||||
|
|
||||||
// Enable it once, it'll get disabled on the next drag
|
|
||||||
raf(() => {
|
|
||||||
this.enableAnimation();
|
|
||||||
if (this.itemSlidingContent) {
|
|
||||||
this.itemSlidingContent.style[CSS.transform] = 'translateX(0)';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
open(amt) {
|
|
||||||
let el = this.itemSlidingContent;
|
|
||||||
this.openAmount = amt || 0;
|
|
||||||
|
|
||||||
if (this.list) {
|
|
||||||
this.list.setOpenItem(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (amt === '') {
|
|
||||||
el.style[CSS.transform] = '';
|
|
||||||
} else {
|
|
||||||
el.style[CSS.transform] = 'translateX(' + -amt + 'px)';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isOpen() {
|
|
||||||
return this.openAmount > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
getOpenAmt() {
|
|
||||||
return this.openAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
disableAnimation() {
|
|
||||||
this.itemSlidingContent.style[CSS.transition] = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
enableAnimation() {
|
|
||||||
// Clear the explicit transition, allow for CSS one to take over
|
|
||||||
this.itemSlidingContent.style[CSS.transition] = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User did a touchstart
|
|
||||||
*/
|
|
||||||
didTouch() {
|
|
||||||
if (this.isOpen()) {
|
|
||||||
this.close();
|
|
||||||
this.didClose = true;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
let openItem = this.list.getOpenItem();
|
|
||||||
if (openItem && openItem !== this) {
|
|
||||||
this.didClose = true;
|
|
||||||
}
|
|
||||||
if (this.list) {
|
|
||||||
this.list.closeOpenItem();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class ItemSlideGesture extends DragGesture {
|
|
||||||
constructor(item: ItemSliding, el: Element, zone) {
|
|
||||||
super(el, {
|
|
||||||
direction: 'x',
|
|
||||||
threshold: el.offsetWidth
|
|
||||||
});
|
|
||||||
|
|
||||||
this.item = item;
|
|
||||||
this.canDrag = true;
|
|
||||||
this.listen();
|
|
||||||
|
|
||||||
zone.runOutsideAngular(() => {
|
|
||||||
let touchStart = (e) => {
|
|
||||||
this.item.didTouch();
|
|
||||||
raf(() => {
|
|
||||||
this.item.itemOptionsWidth = this.item.itemOptions && this.item.itemOptions.offsetWidth || 0;
|
|
||||||
})
|
|
||||||
};
|
|
||||||
el.addEventListener('touchstart', touchStart);
|
|
||||||
el.addEventListener('mousedown', touchStart);
|
|
||||||
|
|
||||||
let touchEnd = (e) => {
|
|
||||||
// If we have a touch end and the item is closing,
|
|
||||||
// prevent default to stop a click from triggering
|
|
||||||
if(this.item.didClose) {
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
this.item.didClose = false;
|
|
||||||
};
|
|
||||||
el.addEventListener('touchend', touchEnd);
|
|
||||||
el.addEventListener('mouseup', touchEnd);
|
|
||||||
el.addEventListener('mouseout', touchEnd);
|
|
||||||
el.addEventListener('mouseleave', touchEnd);
|
|
||||||
el.addEventListener('touchcancel', touchEnd);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onDragStart(ev) {
|
|
||||||
if (this.item.didClose) { return; }
|
|
||||||
|
|
||||||
if (!this.item.itemOptionsWidth) { return; }
|
|
||||||
|
|
||||||
this.slide = {};
|
|
||||||
|
|
||||||
this.slide.offsetX = this.item.getOpenAmt();
|
|
||||||
this.slide.startX = ev.center[this.direction];
|
|
||||||
this.slide.started = true;
|
|
||||||
|
|
||||||
this.item.disableAnimation();
|
|
||||||
}
|
|
||||||
|
|
||||||
onDrag(ev) {
|
|
||||||
if (!this.slide || !this.slide.started) return;
|
|
||||||
|
|
||||||
this.slide.x = ev.center[this.direction];
|
|
||||||
this.slide.delta = this.slide.x - this.slide.startX;
|
|
||||||
|
|
||||||
let newX = Math.max(0, this.slide.offsetX - this.slide.delta);
|
|
||||||
|
|
||||||
let buttonsWidth = this.item.itemOptionsWidth;
|
|
||||||
|
|
||||||
if (newX > this.item.itemOptionsWidth) {
|
|
||||||
// Calculate the new X position, capped at the top of the buttons
|
|
||||||
newX = -Math.min(-buttonsWidth, -buttonsWidth + (((this.slide.delta + buttonsWidth) * 0.4)));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.item.open(newX);
|
|
||||||
}
|
|
||||||
|
|
||||||
onDragEnd(ev) {
|
|
||||||
if (!this.slide || !this.slide.started) return;
|
|
||||||
|
|
||||||
let buttonsWidth = this.item.itemOptionsWidth;
|
|
||||||
|
|
||||||
// If we are currently dragging, we want to snap back into place
|
|
||||||
// The final resting point X will be the width of the exposed buttons
|
|
||||||
var restingPoint = this.item.itemOptionsWidth;
|
|
||||||
|
|
||||||
// Check if the drag didn't clear the buttons mid-point
|
|
||||||
// and we aren't moving fast enough to swipe open
|
|
||||||
if (this.item.openAmount < (buttonsWidth / 2)) {
|
|
||||||
|
|
||||||
// If we are going left but too slow, or going right, go back to resting
|
|
||||||
if (ev.direction & Hammer.DIRECTION_RIGHT) {
|
|
||||||
// Left
|
|
||||||
restingPoint = 0;
|
|
||||||
} else if (Math.abs(ev.velocityX) < 0.3) {
|
|
||||||
// Right
|
|
||||||
restingPoint = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
raf(() => {
|
|
||||||
if (restingPoint === 0) {
|
|
||||||
// Reset to zero
|
|
||||||
this.item.open('');
|
|
||||||
var buttons = this.item.itemOptions;
|
|
||||||
clearTimeout(this.hideButtonsTimeout);
|
|
||||||
this.hideButtonsTimeout = setTimeout(() => {
|
|
||||||
buttons && buttons.classList.add('invisible');
|
|
||||||
}, 250);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.item.open(restingPoint);
|
|
||||||
}
|
|
||||||
this.item.enableAnimation();
|
|
||||||
|
|
||||||
this.slide = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -134,24 +134,6 @@ ion-input.item {
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The hidden right-side buttons that can be exposed under a list item
|
|
||||||
* with dragging.
|
|
||||||
*/
|
|
||||||
ion-item-sliding-content {
|
|
||||||
display: block;
|
|
||||||
z-index: $z-index-item-options + 1;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
ion-item-options {
|
|
||||||
display: flex;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: $z-index-item-options;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TEMP hack for https://github.com/angular/angular/issues/4582
|
// TEMP hack for https://github.com/angular/angular/issues/4582
|
||||||
[item-right] {
|
[item-right] {
|
||||||
|
@ -163,26 +163,6 @@ ion-note {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ion-item-sliding.item {
|
|
||||||
padding-left: 0;
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ion-item-sliding-content {
|
|
||||||
background-color: $item-ios-sliding-content-bg;
|
|
||||||
padding-right: ($item-ios-padding-right / 2);
|
|
||||||
padding-left: ($item-ios-padding-left / 2);
|
|
||||||
display: flex;
|
|
||||||
min-height: 42px;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
transition: $item-ios-sliding-transition;
|
|
||||||
|
|
||||||
// To allow the hairlines through
|
|
||||||
margin-top: 1px;
|
|
||||||
margin-bottom: 1px;
|
|
||||||
}
|
|
||||||
ion-item-options {
|
ion-item-options {
|
||||||
button, [button] {
|
button, [button] {
|
||||||
min-height: calc(100% - 2px);
|
min-height: calc(100% - 2px);
|
||||||
@ -204,8 +184,7 @@ ion-note {
|
|||||||
|
|
||||||
.item.activated,
|
.item.activated,
|
||||||
a.item.activated,
|
a.item.activated,
|
||||||
button.item.activated,
|
button.item.activated {
|
||||||
.item.activated ion-item-sliding-content {
|
|
||||||
background-color: $item-ios-activated-background-color;
|
background-color: $item-ios-activated-background-color;
|
||||||
transition-duration: 0ms;
|
transition-duration: 0ms;
|
||||||
}
|
}
|
||||||
@ -219,25 +198,13 @@ button.item {
|
|||||||
.list,
|
.list,
|
||||||
ion-card {
|
ion-card {
|
||||||
button[ion-item]:not([detail-none]),
|
button[ion-item]:not([detail-none]),
|
||||||
a[ion-item]:not([detail-none]),
|
a[ion-item]:not([detail-none]) {
|
||||||
[detail-push]:not(ion-item-sliding) {
|
|
||||||
@include ios-detail-push-icon($item-ios-detail-push-color);
|
@include ios-detail-push-icon($item-ios-detail-push-color);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: right ($item-ios-padding-right - 2) center;
|
background-position: right ($item-ios-padding-right - 2) center;
|
||||||
background-size: 14px 14px;
|
background-size: 14px 14px;
|
||||||
margin-right: 32px;
|
margin-right: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-item-sliding[detail-push] {
|
|
||||||
|
|
||||||
ion-item-sliding-content {
|
|
||||||
@include ios-detail-push-icon($item-ios-detail-push-color);
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: right ($item-ios-padding-right - 2) center;
|
|
||||||
background-size: 14px 14px;
|
|
||||||
margin-right: 32px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hairlines for iOS need to be set at 0.55px to show on iPhone 6 and 6 Plus
|
// Hairlines for iOS need to be set at 0.55px to show on iPhone 6 and 6 Plus
|
||||||
@ -252,11 +219,6 @@ ion-card {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-item-sliding-content {
|
|
||||||
margin-top: 0.55px;
|
|
||||||
margin-bottom: 0.55px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ion-header + .item {
|
ion-header + .item {
|
||||||
border-top-width: 0.55px;
|
border-top-width: 0.55px;
|
||||||
|
|
||||||
|
@ -207,24 +207,6 @@ ion-note {
|
|||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-item-sliding.item {
|
|
||||||
padding-left: 0;
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
ion-item-sliding-content {
|
|
||||||
background-color: $item-md-sliding-content-bg;
|
|
||||||
padding-right: ($item-md-padding-right / 2);
|
|
||||||
padding-left: ($item-md-padding-left / 2);
|
|
||||||
display: flex;
|
|
||||||
min-height: 42px;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
transition: $item-md-sliding-transition;
|
|
||||||
|
|
||||||
// To allow the hairlines through
|
|
||||||
margin-top: 1px;
|
|
||||||
margin-bottom: 1px;
|
|
||||||
}
|
|
||||||
ion-item-options {
|
ion-item-options {
|
||||||
button, [button] {
|
button, [button] {
|
||||||
height: calc(100% - 2px);
|
height: calc(100% - 2px);
|
||||||
@ -246,15 +228,13 @@ ion-note {
|
|||||||
|
|
||||||
.item,
|
.item,
|
||||||
a.item,
|
a.item,
|
||||||
button.item,
|
button.item {
|
||||||
.item ion-item-sliding-content {
|
transition: background-color $button-md-transition-duration $button-md-animation-curve, transform 300ms;
|
||||||
transition: background-color $button-md-transition-duration $button-md-animation-curve;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.item.activated,
|
.item.activated,
|
||||||
a.item.activated,
|
a.item.activated,
|
||||||
button.item.activated,
|
button.item.activated {
|
||||||
.item.activated ion-item-sliding-content {
|
|
||||||
background-color: $item-md-activated-background-color;
|
background-color: $item-md-activated-background-color;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,35 @@
|
|||||||
import {App} from 'ionic/ionic';
|
import {App, IonicApp} from 'ionic/ionic';
|
||||||
|
|
||||||
|
|
||||||
@App({
|
@App({
|
||||||
templateUrl: 'main.html'
|
templateUrl: 'main.html'
|
||||||
})
|
})
|
||||||
class E2EApp {
|
class E2EApp {
|
||||||
constructor() {
|
constructor(private app: IonicApp) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.shouldShow = true;
|
this.shouldShow = true;
|
||||||
}, 10);
|
}, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
closeOpened() {
|
||||||
|
this.app.getComponent('myList').closeSlidingItems();
|
||||||
|
}
|
||||||
|
|
||||||
getItems() {
|
getItems() {
|
||||||
console.log('getItems');
|
|
||||||
return [0,1];
|
return [0,1];
|
||||||
}
|
}
|
||||||
|
|
||||||
didClick(e) {
|
didClick(ev, item) {
|
||||||
console.log('CLICK', e.defaultPrevented, e)
|
console.log('CLICK', ev.defaultPrevented, ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
archive(e) {
|
archive(ev, item) {
|
||||||
console.log('Accept', e);
|
console.log('Archive', ev, item);
|
||||||
|
item.close();
|
||||||
}
|
}
|
||||||
del(e) {
|
|
||||||
console.log('Delete', e);
|
del(ev, item) {
|
||||||
|
console.log('Delete', ev, item);
|
||||||
|
item.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,78 +1,100 @@
|
|||||||
<ion-toolbar><ion-title>Sliding Items</ion-title></ion-toolbar>
|
<ion-toolbar><ion-title>Sliding Items</ion-title></ion-toolbar>
|
||||||
|
|
||||||
<ion-list>
|
<ion-content>
|
||||||
|
|
||||||
<ion-item-sliding text-wrap detail-push (click)="didClick($event)">
|
<ion-list id="myList">
|
||||||
|
|
||||||
|
<ion-item-sliding #item>
|
||||||
|
<ion-item text-wrap detail-push (click)="didClick($event, item)">
|
||||||
<h3>Max Lynch</h3>
|
<h3>Max Lynch</h3>
|
||||||
<p>
|
<p>
|
||||||
Hey do you want to go to the game tonight?
|
Hey do you want to go to the game tonight?
|
||||||
</p>
|
</p>
|
||||||
|
</ion-item>
|
||||||
<ion-item-options>
|
<ion-item-options>
|
||||||
<button primary (click)="archive($event)">Archive</button>
|
<button primary (click)="archive($event, item)">Archive</button>
|
||||||
<button danger (click)="del($event)">Delete</button>
|
<button danger (click)="del($event, item)">Delete</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
</ion-item-sliding>
|
||||||
|
|
||||||
<ion-item-sliding text-wrap detail-push class="activated">
|
<ion-item-sliding #item>
|
||||||
|
<ion-item text-wrap detail-push class="activated">
|
||||||
<h3>Adam Bradley</h3>
|
<h3>Adam Bradley</h3>
|
||||||
<p>
|
<p>
|
||||||
I think I figured out how to get more Mountain Dew
|
I think I figured out how to get more Mountain Dew
|
||||||
</p>
|
</p>
|
||||||
|
</ion-item>
|
||||||
<ion-item-options>
|
<ion-item-options>
|
||||||
<button primary>Archive</button>
|
<button primary (click)="archive($event, item)">Archive</button>
|
||||||
<button danger><icon trash></icon></button>
|
<button danger (click)="del($event, item)"><icon trash></icon></button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
</ion-item-sliding>
|
||||||
|
|
||||||
<ion-item-sliding text-wrap detail-push *ng-if="shouldShow">
|
<ion-item-sliding text-wrap detail-push *ng-if="shouldShow" #item>
|
||||||
|
<ion-item>
|
||||||
<h3>Ben Sperry</h3>
|
<h3>Ben Sperry</h3>
|
||||||
<p>
|
<p>
|
||||||
I like paper
|
I like paper
|
||||||
</p>
|
</p>
|
||||||
|
</ion-item>
|
||||||
<ion-item-options>
|
<ion-item-options>
|
||||||
<button primary>Archive</button>
|
<button primary (click)="archive($event, item)">Archive</button>
|
||||||
<button danger>Delete</button>
|
<button danger (click)="del($event, item)">Delete</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
</ion-item-sliding>
|
||||||
|
|
||||||
<ion-item-sliding>
|
<ion-item-sliding #item>
|
||||||
|
<ion-item>
|
||||||
<icon mail item-left></icon>
|
<icon mail item-left></icon>
|
||||||
One Line w/ Icon, div only text
|
One Line w/ Icon, div only text
|
||||||
|
</ion-item>
|
||||||
<ion-item-options>
|
<ion-item-options>
|
||||||
<button primary>Archive</button>
|
<button primary (click)="archive($event, item)">Archive</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
</ion-item-sliding>
|
||||||
|
|
||||||
<ion-item-sliding>
|
<ion-item-sliding #item>
|
||||||
|
<ion-item>
|
||||||
<ion-avatar item-left>
|
<ion-avatar item-left>
|
||||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==">
|
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==">
|
||||||
</ion-avatar>
|
</ion-avatar>
|
||||||
One Line w/ Avatar, div only text
|
One Line w/ Avatar, div only text
|
||||||
|
</ion-item>
|
||||||
<ion-item-options>
|
<ion-item-options>
|
||||||
<button primary>Archive</button>
|
<button primary (click)="archive($event, item)">Archive</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
</ion-item-sliding>
|
||||||
|
|
||||||
<ion-item-sliding>
|
<ion-item-sliding #item>
|
||||||
|
<ion-item>
|
||||||
<ion-thumbnail item-left>
|
<ion-thumbnail item-left>
|
||||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==">
|
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==">
|
||||||
</ion-thumbnail>
|
</ion-thumbnail>
|
||||||
<h2>Two Lines w/ Thumbnail, H2 Header</h2>
|
<h2>Two Lines w/ Thumbnail, H2 Header</h2>
|
||||||
<p>Paragraph text.</p>
|
<p>Paragraph text.</p>
|
||||||
|
</ion-item>
|
||||||
<ion-item-options>
|
<ion-item-options>
|
||||||
<button primary>Archive</button>
|
<button primary (click)="archive($event, item)">Archive</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
</ion-item-sliding>
|
||||||
|
|
||||||
<ion-item-sliding text-wrap detail-push *ng-for="#item of getItems()">
|
<ion-item-sliding *ng-for="#item of getItems()">
|
||||||
|
<ion-item text-wrap detail-push>
|
||||||
<h3>ng-for {{item}}</h3>
|
<h3>ng-for {{item}}</h3>
|
||||||
|
</ion-item>
|
||||||
<ion-item-options>
|
<ion-item-options>
|
||||||
<button primary>Archive</button>
|
<button primary (click)="archive($event, item)">Archive</button>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
</ion-item-sliding>
|
||||||
|
|
||||||
</ion-list>
|
</ion-list>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<button (click)="closeOpened()">Close opened items</button>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</ion-content>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
img {
|
img {
|
||||||
height: 100px;
|
height: 100px;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import {Directive, ElementRef, Renderer} from 'angular2/angular2';
|
import {Directive, ElementRef, Renderer, NgZone} from 'angular2/angular2';
|
||||||
|
|
||||||
import {Ion} from '../ion';
|
import {Ion} from '../ion';
|
||||||
import {Config} from '../../config/config';
|
import {Config} from '../../config/config';
|
||||||
import {ListVirtualScroll} from './virtual';
|
import {ListVirtualScroll} from './virtual';
|
||||||
|
import {ItemSlidingGesture} from '../item/item-sliding-gesture';
|
||||||
import * as util from 'ionic/util';
|
import * as util from 'ionic/util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,7 +31,7 @@ export class List extends Ion {
|
|||||||
* @param {ElementRef} elementRef TODO
|
* @param {ElementRef} elementRef TODO
|
||||||
* @param {Config} config TODO
|
* @param {Config} config TODO
|
||||||
*/
|
*/
|
||||||
constructor(elementRef: ElementRef, config: Config, renderer: Renderer) {
|
constructor(elementRef: ElementRef, config: Config, renderer: Renderer, private zone: NgZone) {
|
||||||
super(elementRef, config);
|
super(elementRef, config);
|
||||||
renderer.setElementClass(elementRef, 'list', true);
|
renderer.setElementClass(elementRef, 'list', true);
|
||||||
this.ele = elementRef.nativeElement;
|
this.ele = elementRef.nativeElement;
|
||||||
@ -48,6 +49,12 @@ export class List extends Ion {
|
|||||||
this._initVirtualScrolling();
|
this._initVirtualScrolling();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDestroy() {
|
||||||
|
this.ele = null;
|
||||||
|
this.slidingGesture && this.slidingGesture.unlisten();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* TODO
|
* TODO
|
||||||
@ -68,20 +75,32 @@ export class List extends Ion {
|
|||||||
this.itemTemplate = item;
|
this.itemTemplate = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
enableSlidingItems(shouldEnable) {
|
||||||
* Keeps track of any open item (a sliding item, for example), to close it later
|
this._enableSliding = shouldEnable;
|
||||||
*/
|
|
||||||
setOpenItem(item) {
|
if (this._init) {
|
||||||
this.openItem = item;
|
if (shouldEnable) {
|
||||||
}
|
this.zone.runOutsideAngular(() => {
|
||||||
closeOpenItem() {
|
setTimeout(() => {
|
||||||
if(this.openItem) {
|
this.slidingGesture = new ItemSlidingGesture(this, this.ele);
|
||||||
this.openItem.close(true);
|
});
|
||||||
this.openItem = null;
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.slidingGesture && this.slidingGesture.unlisten();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getOpenItem() {
|
}
|
||||||
return this.openItem;
|
|
||||||
|
closeSlidingItems() {
|
||||||
|
this.slidingGesture && this.slidingGesture.closeOpened();
|
||||||
|
}
|
||||||
|
|
||||||
|
afterViewInit() {
|
||||||
|
this._init = true;
|
||||||
|
if (this._enableSliding) {
|
||||||
|
this.enableSlidingItems(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,6 +116,4 @@ export class List extends Ion {
|
|||||||
'[attr.id]': 'id'
|
'[attr.id]': 'id'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
export class ListHeader {
|
export class ListHeader {}
|
||||||
|
|
||||||
}
|
|
||||||
|
@ -8,14 +8,24 @@
|
|||||||
<ion-navbar *navbar>
|
<ion-navbar *navbar>
|
||||||
<ion-title>Heart</ion-title>
|
<ion-title>Heart</ion-title>
|
||||||
</ion-navbar>
|
</ion-navbar>
|
||||||
<ion-content padding>
|
<ion-content>
|
||||||
<h2>Tab 1</h2>
|
<ion-list>
|
||||||
|
<ion-header>
|
||||||
|
Tab 1
|
||||||
|
</ion-header>
|
||||||
|
<ion-item *ng-for="#i of items">Item {{i}} {{i}} {{i}} {{i}}</ion-item>
|
||||||
|
</ion-list>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
class Tab1 {
|
class Tab1 {
|
||||||
constructor(nav: NavController) {
|
constructor(nav: NavController) {
|
||||||
this.nav = nav;
|
this.nav = nav;
|
||||||
|
|
||||||
|
this.items = [];
|
||||||
|
for(var i = 1; i <= 250; i++) {
|
||||||
|
this.items.push(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,16 +35,35 @@ class Tab1 {
|
|||||||
@Page({
|
@Page({
|
||||||
template: `
|
template: `
|
||||||
<ion-navbar *navbar>
|
<ion-navbar *navbar>
|
||||||
<ion-title>Star</ion-title>
|
<ion-title>Schedule</ion-title>
|
||||||
</ion-navbar>
|
</ion-navbar>
|
||||||
<ion-content padding>
|
<ion-content>
|
||||||
<h2>Tab 2</h2>
|
<ion-list>
|
||||||
|
<ion-item-sliding *ng-for="#session of sessions" #sliding-item>
|
||||||
|
<ion-item>
|
||||||
|
<h3>{{session.name}} {{session.name}} {{session.name}}</h3>
|
||||||
|
<p>{{session.location}} {{session.location}} {{session.location}}</p>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-options>
|
||||||
|
<button primary>Speaker<br>Info</button>
|
||||||
|
<button secondary>Add to<br>Favorites</button>
|
||||||
|
</ion-item-options>
|
||||||
|
</ion-item-sliding>
|
||||||
|
</ion-list>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
class Tab2 {
|
class Tab2 {
|
||||||
constructor(nav: NavController) {
|
constructor(nav: NavController) {
|
||||||
this.nav = nav;
|
this.nav = nav;
|
||||||
|
|
||||||
|
this.sessions = [];
|
||||||
|
for(var i = 1; i <= 250; i++) {
|
||||||
|
this.sessions.push({
|
||||||
|
name: 'Name ' + i,
|
||||||
|
location: 'Location: ' + i
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,8 +105,8 @@ class Tab3 {
|
|||||||
</ion-menu>
|
</ion-menu>
|
||||||
|
|
||||||
<ion-tabs #content>
|
<ion-tabs #content>
|
||||||
<ion-tab tab-title="Heart" tab-icon="heart" [root]="root1"></ion-tab>
|
<ion-tab tab-title="Plain List" tab-icon="star" [root]="root1"></ion-tab>
|
||||||
<ion-tab tab-title="Star" tab-icon="star" [root]="root2"></ion-tab>
|
<ion-tab tab-title="Schedule" tab-icon="globe" [root]="root2"></ion-tab>
|
||||||
<ion-tab tab-title="Stopwatch" tab-icon="stopwatch" [root]="root3"></ion-tab>
|
<ion-tab tab-title="Stopwatch" tab-icon="stopwatch" [root]="root3"></ion-tab>
|
||||||
</ion-tabs>
|
</ion-tabs>
|
||||||
`
|
`
|
||||||
|
@ -73,6 +73,8 @@ export class Activator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
disableActivated(ev) {
|
disableActivated(ev) {
|
||||||
|
if (ev.defaultPrevented) return true;
|
||||||
|
|
||||||
let targetEle = ev.target;
|
let targetEle = ev.target;
|
||||||
for (let x = 0; x < 4; x++) {
|
for (let x = 0; x < 4; x++) {
|
||||||
if (!targetEle) break;
|
if (!targetEle) break;
|
||||||
|
@ -18,7 +18,3 @@ md-ripple {
|
|||||||
|
|
||||||
transform: scale(0.001) translateZ(0);
|
transform: scale(0.001) translateZ(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-item-sliding md-ripple {
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
@ -7,8 +7,8 @@ let startCoord = null;
|
|||||||
let pointerTolerance = 4;
|
let pointerTolerance = 4;
|
||||||
let lastTouch = 0;
|
let lastTouch = 0;
|
||||||
let lastActivated = 0;
|
let lastActivated = 0;
|
||||||
let disableNativeClickTime = 0;
|
let disableNativeClickUntil = 0;
|
||||||
let disableNativeClickLimit = 1000;
|
let disableNativeClickAmount = 3000;
|
||||||
let activator = null;
|
let activator = null;
|
||||||
let isEnabled = false;
|
let isEnabled = false;
|
||||||
let app = null;
|
let app = null;
|
||||||
@ -45,13 +45,13 @@ function touchStart(ev) {
|
|||||||
function touchEnd(ev) {
|
function touchEnd(ev) {
|
||||||
touchAction();
|
touchAction();
|
||||||
|
|
||||||
if (isEnabled && startCoord && app.isEnabled()) {
|
if (isEnabled && startCoord && app.isEnabled() && !ev.defaultPrevented) {
|
||||||
let endCoord = pointerCoord(ev);
|
let endCoord = pointerCoord(ev);
|
||||||
|
|
||||||
if (!hasPointerMoved(pointerTolerance, startCoord, endCoord)) {
|
if (!hasPointerMoved(pointerTolerance, startCoord, endCoord)) {
|
||||||
console.debug('create click from touch');
|
console.debug('create click from touch');
|
||||||
|
|
||||||
setDisableNativeClick();;
|
disableNativeClickUntil = Date.now() + disableNativeClickAmount;
|
||||||
|
|
||||||
let clickEvent = doc.createEvent('MouseEvents');
|
let clickEvent = doc.createEvent('MouseEvents');
|
||||||
clickEvent.initMouseEvent('click', true, true, win, 1, 0, 0, endCoord.x, endCoord.y, false, false, false, false, 0, null);
|
clickEvent.initMouseEvent('click', true, true, win, 1, 0, 0, endCoord.x, endCoord.y, false, false, false, false, 0, null);
|
||||||
@ -74,7 +74,7 @@ function mouseDown(ev) {
|
|||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
} else if (lastTouch + disableNativeClickLimit < Date.now()) {
|
} else if (lastTouch + disableNativeClickAmount < Date.now()) {
|
||||||
pointerStart(ev);
|
pointerStart(ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,7 +86,7 @@ function mouseUp(ev) {
|
|||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastTouch + disableNativeClickLimit < Date.now()) {
|
if (lastTouch + disableNativeClickAmount < Date.now()) {
|
||||||
pointerEnd(ev);
|
pointerEnd(ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,7 +127,6 @@ function pointerCancel(ev) {
|
|||||||
console.debug('pointerCancel from', ev.type);
|
console.debug('pointerCancel from', ev.type);
|
||||||
activator.clearState();
|
activator.clearState();
|
||||||
moveListeners(false);
|
moveListeners(false);
|
||||||
setDisableNativeClick();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveListeners(shouldAdd) {
|
function moveListeners(shouldAdd) {
|
||||||
@ -139,12 +138,8 @@ function moveListeners(shouldAdd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setDisableNativeClick() {
|
|
||||||
disableNativeClickTime = Date.now() + disableNativeClickLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isDisabledNativeClick() {
|
function isDisabledNativeClick() {
|
||||||
return disableNativeClickTime > Date.now();
|
return disableNativeClickUntil > Date.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
function click(ev) {
|
function click(ev) {
|
||||||
|
@ -15,7 +15,7 @@ import {Tab} from '../components/tabs/tab';
|
|||||||
import {List, ListHeader} from '../components/list/list';
|
import {List, ListHeader} from '../components/list/list';
|
||||||
import {Item} from '../components/item/item';
|
import {Item} from '../components/item/item';
|
||||||
import {ItemGroup, ItemGroupTitle} from '../components/item/item-group';
|
import {ItemGroup, ItemGroupTitle} from '../components/item/item-group';
|
||||||
import {ItemSliding, ItemSlidingOptionButton} from '../components/item/item-sliding';
|
import {ItemSliding} from '../components/item/item-sliding';
|
||||||
import {Toolbar, ToolbarTitle, ToolbarItem} from '../components/toolbar/toolbar';
|
import {Toolbar, ToolbarTitle, ToolbarItem} from '../components/toolbar/toolbar';
|
||||||
import {Icon} from '../components/icon/icon';
|
import {Icon} from '../components/icon/icon';
|
||||||
import {Checkbox} from '../components/checkbox/checkbox';
|
import {Checkbox} from '../components/checkbox/checkbox';
|
||||||
@ -60,7 +60,6 @@ export const IONIC_DIRECTIVES = [
|
|||||||
ItemGroup,
|
ItemGroup,
|
||||||
ItemGroupTitle,
|
ItemGroupTitle,
|
||||||
ItemSliding,
|
ItemSliding,
|
||||||
ItemSlidingOptionButton,
|
|
||||||
|
|
||||||
// Slides
|
// Slides
|
||||||
Slides,
|
Slides,
|
||||||
|
@ -10,24 +10,24 @@ export class DragGesture extends Gesture {
|
|||||||
|
|
||||||
listen() {
|
listen() {
|
||||||
super.listen();
|
super.listen();
|
||||||
|
|
||||||
this.on('panstart', ev => {
|
this.on('panstart', ev => {
|
||||||
if (this.onDragStart(ev) !== false) {
|
if (this.onDragStart(ev) !== false) {
|
||||||
this.dragging = true;
|
this.dragging = true;
|
||||||
}
|
}
|
||||||
// ev.stopPropagation();
|
});
|
||||||
})
|
|
||||||
this.on('panmove', ev => {
|
this.on('panmove', ev => {
|
||||||
if (!this.dragging) return;
|
if (!this.dragging) return;
|
||||||
if (this.onDrag(ev) === false) {
|
if (this.onDrag(ev) === false) {
|
||||||
this.dragging = false;
|
this.dragging = false;
|
||||||
}
|
}
|
||||||
// ev.stopPropagation()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.on('panend', ev => {
|
this.on('panend', ev => {
|
||||||
if (!this.dragging) return;
|
if (!this.dragging) return;
|
||||||
this.onDragEnd(ev);
|
this.onDragEnd(ev);
|
||||||
this.dragging = false;
|
this.dragging = false;
|
||||||
// ev.stopPropagation()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
"components/icon/icon",
|
"components/icon/icon",
|
||||||
"components/item/item",
|
"components/item/item",
|
||||||
"components/item/item-media",
|
"components/item/item-media",
|
||||||
|
"components/item/item-sliding",
|
||||||
"components/grid/grid",
|
"components/grid/grid",
|
||||||
"components/text-input/text-input",
|
"components/text-input/text-input",
|
||||||
"components/text-input/label",
|
"components/text-input/label",
|
||||||
|
@ -199,25 +199,25 @@ export function hasFocusedTextInput() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function closest(ele, selector) {
|
let matchesFn;
|
||||||
var matchesFn;
|
['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector'].some(fn => {
|
||||||
|
if (typeof document.documentElement[fn] == 'function') {
|
||||||
// find vendor prefix
|
|
||||||
['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
|
|
||||||
if (typeof document.body[fn] == 'function') {
|
|
||||||
matchesFn = fn;
|
matchesFn = fn;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
});
|
||||||
})
|
|
||||||
|
export function closest(ele, selector, checkSelf) {
|
||||||
|
if (ele && matchesFn) {
|
||||||
|
|
||||||
// traverse parents
|
// traverse parents
|
||||||
|
ele = (checkSelf ? ele : ele.parentElement);
|
||||||
|
|
||||||
while (ele !== null) {
|
while (ele !== null) {
|
||||||
parent = ele.parentElement;
|
if (ele[matchesFn](selector)) {
|
||||||
if (parent!==null && parent[matchesFn](selector)) {
|
return ele;
|
||||||
return parent;
|
}
|
||||||
|
ele = ele.parentElement;
|
||||||
}
|
}
|
||||||
ele = parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -233,10 +233,10 @@ export function removeElement(ele) {
|
|||||||
* to reduce DOM reads. Cache is cleared on a window resize.
|
* to reduce DOM reads. Cache is cleared on a window resize.
|
||||||
* @param {TODO} ele TODO
|
* @param {TODO} ele TODO
|
||||||
*/
|
*/
|
||||||
export function getDimensions(ion) {
|
export function getDimensions(ion, ele) {
|
||||||
if (!ion._dimId) {
|
if (!ion._dimId) {
|
||||||
ion._dimId = ++dimensionIds;
|
ion._dimId = ++dimensionIds;
|
||||||
if (ion._dimId % 100 === 0) {
|
if (ion._dimId % 1000 === 0) {
|
||||||
// periodically flush dimensions
|
// periodically flush dimensions
|
||||||
flushDimensionCache();
|
flushDimensionCache();
|
||||||
}
|
}
|
||||||
@ -244,7 +244,7 @@ export function getDimensions(ion) {
|
|||||||
|
|
||||||
let dimensions = dimensionCache[ion._dimId];
|
let dimensions = dimensionCache[ion._dimId];
|
||||||
if (!dimensions) {
|
if (!dimensions) {
|
||||||
let ele = ion.getNativeElement();
|
ele = ele || ion.getNativeElement();
|
||||||
dimensions = dimensionCache[ion._dimId] = {
|
dimensions = dimensionCache[ion._dimId] = {
|
||||||
width: ele.offsetWidth,
|
width: ele.offsetWidth,
|
||||||
height: ele.offsetHeight,
|
height: ele.offsetHeight,
|
||||||
|
Reference in New Issue
Block a user