mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
feat(queue): use stencil's queue controller for dom read/writes
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
import { Component, Element, Listen, Method, Prop } from '@stencil/core';
|
import { Component, Element, Listen, Method, Prop } from '@stencil/core';
|
||||||
import { Config, DomController } from '../../index';
|
import { Config, QueueController } from '../../index';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
tag: 'ion-content',
|
tag: 'ion-content',
|
||||||
@ -18,7 +18,7 @@ export class Content {
|
|||||||
@Element() private el: HTMLElement;
|
@Element() private el: HTMLElement;
|
||||||
|
|
||||||
@Prop({ context: 'config' }) config: Config;
|
@Prop({ context: 'config' }) config: Config;
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'queue' }) queue: QueueController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, the content will scroll behind the headers
|
* If true, the content will scroll behind the headers
|
||||||
@ -100,13 +100,13 @@ export class Content {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.fullscreen) {
|
if (this.fullscreen) {
|
||||||
this.dom.raf(() => {
|
this.queue.read(() => {
|
||||||
this.dom.read(this.readDimensions.bind(this));
|
this.queue.read(this.readDimensions.bind(this));
|
||||||
this.dom.write(this.writeDimensions.bind(this));
|
this.queue.write(this.writeDimensions.bind(this));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.cTop = this.cBottom = -1;
|
this.cTop = this.cBottom = -1;
|
||||||
this.dom.write(() => this.scrollEl && this.scrollEl.removeAttribute('style'));
|
this.queue.write(() => this.scrollEl && this.scrollEl.removeAttribute('style'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Component, Event, EventEmitter, EventListenerEnable, Listen, Prop, Watch } from '@stencil/core';
|
import { Component, Event, EventEmitter, EventListenerEnable, Listen, Prop, Watch } from '@stencil/core';
|
||||||
import { assert, now } from '../../utils/helpers';
|
import { assert, now } from '../../utils/helpers';
|
||||||
import { BlockerConfig, BlockerDelegate, DomController, GestureDelegate } from '../../index';
|
import { BlockerConfig, BlockerDelegate, GestureDelegate, QueueController } from '../../index';
|
||||||
import { PanRecognizer } from './recognizers';
|
import { PanRecognizer } from './recognizers';
|
||||||
|
|
||||||
export const BLOCK_ALL: BlockerConfig = {
|
export const BLOCK_ALL: BlockerConfig = {
|
||||||
@ -27,7 +27,7 @@ export class Gesture {
|
|||||||
private blocker: BlockerDelegate|undefined;
|
private blocker: BlockerDelegate|undefined;
|
||||||
|
|
||||||
@Prop({ connect: 'ion-gesture-controller' }) gestureCtrl: HTMLIonGestureControllerElement;
|
@Prop({ connect: 'ion-gesture-controller' }) gestureCtrl: HTMLIonGestureControllerElement;
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'queue' }) queue: QueueController;
|
||||||
@Prop({ context: 'enableListener' }) enableListener: EventListenerEnable;
|
@Prop({ context: 'enableListener' }) enableListener: EventListenerEnable;
|
||||||
|
|
||||||
@Prop() disabled = false;
|
@Prop() disabled = false;
|
||||||
@ -232,7 +232,7 @@ export class Gesture {
|
|||||||
if (!this.isMoveQueued && this.hasFiredStart) {
|
if (!this.isMoveQueued && this.hasFiredStart) {
|
||||||
this.isMoveQueued = true;
|
this.isMoveQueued = true;
|
||||||
this.calcGestureData(ev);
|
this.calcGestureData(ev);
|
||||||
this.dom.write(this.fireOnMove.bind(this));
|
this.queue.write(this.fireOnMove.bind(this));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, Element, Event, EventEmitter, EventListenerEnable, Listen, Method, Prop, State, Watch } from '@stencil/core';
|
import { Component, Element, Event, EventEmitter, EventListenerEnable, Listen, Method, Prop, State, Watch } from '@stencil/core';
|
||||||
import { DomController } from '../../index';
|
import { QueueController } from '../../index';
|
||||||
|
|
||||||
const enum Position {
|
const enum Position {
|
||||||
Top = 'top',
|
Top = 'top',
|
||||||
@ -22,7 +22,7 @@ export class InfiniteScroll {
|
|||||||
@Element() private el: HTMLElement;
|
@Element() private el: HTMLElement;
|
||||||
@State() isLoading = false;
|
@State() isLoading = false;
|
||||||
|
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'queue' }) queue: QueueController;
|
||||||
@Prop({ context: 'enableListener' }) enableListener: EventListenerEnable;
|
@Prop({ context: 'enableListener' }) enableListener: EventListenerEnable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,7 +92,7 @@ export class InfiniteScroll {
|
|||||||
this.thresholdChanged(this.threshold);
|
this.thresholdChanged(this.threshold);
|
||||||
this.enableScrollEvents(!this.disabled);
|
this.enableScrollEvents(!this.disabled);
|
||||||
if (this.position === Position.Top) {
|
if (this.position === Position.Top) {
|
||||||
this.dom.write(() => this.scrollEl && this.scrollEl.scrollToBottom(0));
|
this.queue.write(() => this.scrollEl && this.scrollEl.scrollToBottom(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,14 +179,14 @@ export class InfiniteScroll {
|
|||||||
const prev = scrollEl.scrollHeight - scrollEl.scrollTop;
|
const prev = scrollEl.scrollHeight - scrollEl.scrollTop;
|
||||||
|
|
||||||
// ******** DOM READ ****************
|
// ******** DOM READ ****************
|
||||||
this.dom.read(() => {
|
this.queue.read(() => {
|
||||||
// UI has updated, save the new content dimensions
|
// UI has updated, save the new content dimensions
|
||||||
const scrollHeight = scrollEl.scrollHeight;
|
const scrollHeight = scrollEl.scrollHeight;
|
||||||
// New content was added on top, so the scroll position should be changed immediately to prevent it from jumping around
|
// New content was added on top, so the scroll position should be changed immediately to prevent it from jumping around
|
||||||
const newScrollTop = scrollHeight - prev;
|
const newScrollTop = scrollHeight - prev;
|
||||||
|
|
||||||
// ******** DOM WRITE ****************
|
// ******** DOM WRITE ****************
|
||||||
this.dom.write(() => {
|
this.queue.write(() => {
|
||||||
scrollEl.scrollTop = newScrollTop;
|
scrollEl.scrollTop = newScrollTop;
|
||||||
this.isBusy = false;
|
this.isBusy = false;
|
||||||
});
|
});
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
} from './nav-util';
|
} from './nav-util';
|
||||||
|
|
||||||
import { ViewController, matches } from './view-controller';
|
import { ViewController, matches } from './view-controller';
|
||||||
import { Animation, ComponentProps, Config, DomController, FrameworkDelegate, GestureDetail, NavOutlet } from '../..';
|
import { Animation, ComponentProps, Config, FrameworkDelegate, GestureDetail, NavOutlet, QueueController } from '../..';
|
||||||
import { RouteID, RouteWrite, RouterDirection } from '../router/utils/interfaces';
|
import { RouteID, RouteWrite, RouterDirection } from '../router/utils/interfaces';
|
||||||
import { AnimationOptions, ViewLifecycle, lifecycle, transition } from '../../utils/transition';
|
import { AnimationOptions, ViewLifecycle, lifecycle, transition } from '../../utils/transition';
|
||||||
import { assert } from '../../utils/helpers';
|
import { assert } from '../../utils/helpers';
|
||||||
@ -25,7 +25,7 @@ import mdTransitionAnimation from './animations/md.transition';
|
|||||||
export class Nav implements NavOutlet {
|
export class Nav implements NavOutlet {
|
||||||
|
|
||||||
private init = false;
|
private init = false;
|
||||||
private queue: TransitionInstruction[] = [];
|
private transInstr: TransitionInstruction[] = [];
|
||||||
private sbTrns: Animation|undefined;
|
private sbTrns: Animation|undefined;
|
||||||
private useRouter = false;
|
private useRouter = false;
|
||||||
private isTransitioning = false;
|
private isTransitioning = false;
|
||||||
@ -36,7 +36,7 @@ export class Nav implements NavOutlet {
|
|||||||
|
|
||||||
@Element() el: HTMLElement;
|
@Element() el: HTMLElement;
|
||||||
|
|
||||||
@Prop({context: 'dom'}) dom: DomController;
|
@Prop({context: 'queue'}) queue: QueueController;
|
||||||
@Prop({context: 'config'}) config: Config;
|
@Prop({context: 'config'}) config: Config;
|
||||||
@Prop({context: 'window'}) win: Window;
|
@Prop({context: 'window'}) win: Window;
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ export class Nav implements NavOutlet {
|
|||||||
|
|
||||||
// release swipe back gesture and transition
|
// release swipe back gesture and transition
|
||||||
this.sbTrns && this.sbTrns.destroy();
|
this.sbTrns && this.sbTrns.destroy();
|
||||||
this.queue.length = this.views.length = 0;
|
this.transInstr.length = this.views.length = 0;
|
||||||
this.sbTrns = undefined;
|
this.sbTrns = undefined;
|
||||||
this.destroyed = true;
|
this.destroyed = true;
|
||||||
}
|
}
|
||||||
@ -283,7 +283,7 @@ export class Nav implements NavOutlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Enqueue transition instruction
|
// Enqueue transition instruction
|
||||||
this.queue.push(ti);
|
this.transInstr.push(ti);
|
||||||
|
|
||||||
// if there isn't a transition already happening
|
// if there isn't a transition already happening
|
||||||
// then this will kick off this transition
|
// then this will kick off this transition
|
||||||
@ -293,7 +293,7 @@ export class Nav implements NavOutlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private success(result: NavResult, ti: TransitionInstruction) {
|
private success(result: NavResult, ti: TransitionInstruction) {
|
||||||
if (this.queue === null) {
|
if (this.transInstr === null) {
|
||||||
this.fireError('nav controller was destroyed', ti);
|
this.fireError('nav controller was destroyed', ti);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -323,11 +323,11 @@ export class Nav implements NavOutlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private failed(rejectReason: any, ti: TransitionInstruction) {
|
private failed(rejectReason: any, ti: TransitionInstruction) {
|
||||||
if (this.queue === null) {
|
if (this.transInstr === null) {
|
||||||
this.fireError('nav controller was destroyed', ti);
|
this.fireError('nav controller was destroyed', ti);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.queue.length = 0;
|
this.transInstr.length = 0;
|
||||||
this.fireError(rejectReason, ti);
|
this.fireError(rejectReason, ti);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,7 +351,7 @@ export class Nav implements NavOutlet {
|
|||||||
|
|
||||||
// there is no transition happening right now
|
// there is no transition happening right now
|
||||||
// get the next instruction
|
// get the next instruction
|
||||||
const ti = this.queue.shift();
|
const ti = this.transInstr.shift();
|
||||||
if (!ti) {
|
if (!ti) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -689,7 +689,7 @@ export class Nav implements NavOutlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private swipeBackStart() {
|
private swipeBackStart() {
|
||||||
if (this.isTransitioning || this.queue.length > 0) {
|
if (this.isTransitioning || this.transInstr.length > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Component, Element, Prop } from '@stencil/core';
|
import { Component, Element, Prop } from '@stencil/core';
|
||||||
import { DomController, GestureDetail, PickerColumn, PickerColumnOption } from '../../index';
|
|
||||||
import { clamp } from '../../utils/helpers';
|
import { clamp } from '../../utils/helpers';
|
||||||
|
import { GestureDetail, PickerColumn, PickerColumnOption, QueueController } from '../../index';
|
||||||
import { hapticSelectionChanged } from '../../utils';
|
import { hapticSelectionChanged } from '../../utils';
|
||||||
|
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ export class PickerColumnCmp {
|
|||||||
|
|
||||||
@Element() private el: HTMLElement;
|
@Element() private el: HTMLElement;
|
||||||
|
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'queue' }) queue: QueueController;
|
||||||
|
|
||||||
@Prop() col: PickerColumn;
|
@Prop() col: PickerColumn;
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ export class PickerColumnCmp {
|
|||||||
|
|
||||||
if (notLockedIn) {
|
if (notLockedIn) {
|
||||||
// isn't locked in yet, keep decelerating until it is
|
// isn't locked in yet, keep decelerating until it is
|
||||||
this.dom.raf(() => this.decelerate());
|
this.queue.read(() => this.decelerate());
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (this.y % this.optHeight !== 0) {
|
} else if (this.y % this.optHeight !== 0) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, Element, Event, EventEmitter, Method, Prop, State } from '@stencil/core';
|
import { Component, Element, Event, EventEmitter, Method, Prop, State } from '@stencil/core';
|
||||||
import { DomController, GestureDetail } from '../../index';
|
import { GestureDetail, QueueController } from '../../index';
|
||||||
|
|
||||||
export const enum RefresherState {
|
export const enum RefresherState {
|
||||||
Inactive = 1 << 0,
|
Inactive = 1 << 0,
|
||||||
@ -30,7 +30,7 @@ export class Refresher {
|
|||||||
private progress = 0;
|
private progress = 0;
|
||||||
private scrollEl: HTMLElement | null = null;
|
private scrollEl: HTMLElement | null = null;
|
||||||
|
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'queue' }) queue: QueueController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current state which the refresher is in. The refresher's states include:
|
* The current state which the refresher is in. The refresher's states include:
|
||||||
@ -335,7 +335,7 @@ export class Refresher {
|
|||||||
|
|
||||||
private setCss(y: number, duration: string, overflowVisible: boolean, delay: string) {
|
private setCss(y: number, duration: string, overflowVisible: boolean, delay: string) {
|
||||||
this.appliedStyles = (y > 0);
|
this.appliedStyles = (y > 0);
|
||||||
this.dom.write(() => {
|
this.queue.write(() => {
|
||||||
if (this.scrollEl) {
|
if (this.scrollEl) {
|
||||||
const style = this.scrollEl.style;
|
const style = this.scrollEl.style;
|
||||||
style.transform = ((y > 0) ? 'translateY(' + y + 'px) translateZ(0px)' : 'translateZ(0px)');
|
style.transform = ((y > 0) ? 'translateY(' + y + 'px) translateZ(0px)' : 'translateZ(0px)');
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, Element, Prop, State, Watch } from '@stencil/core';
|
import { Component, Element, Prop, State, Watch } from '@stencil/core';
|
||||||
import { DomController, GestureDetail } from '../../index';
|
import { GestureDetail, QueueController } from '../../index';
|
||||||
import { hapticSelectionChanged, hapticSelectionEnd, hapticSelectionStart} from '../../utils/haptic';
|
import { hapticSelectionChanged, hapticSelectionEnd, hapticSelectionStart} from '../../utils/haptic';
|
||||||
|
|
||||||
const AUTO_SCROLL_MARGIN = 60;
|
const AUTO_SCROLL_MARGIN = 60;
|
||||||
@ -44,7 +44,7 @@ export class ReorderGroup {
|
|||||||
|
|
||||||
@Element() private el: HTMLElement;
|
@Element() private el: HTMLElement;
|
||||||
|
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'queue' }) queue: QueueController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, the reorder will be hidden. Defaults to `true`.
|
* If true, the reorder will be hidden. Defaults to `true`.
|
||||||
@ -55,7 +55,7 @@ export class ReorderGroup {
|
|||||||
protected disabledChanged(disabled: boolean) {
|
protected disabledChanged(disabled: boolean) {
|
||||||
if (!disabled) {
|
if (!disabled) {
|
||||||
this.enabled = true;
|
this.enabled = true;
|
||||||
this.dom.raf(() => {
|
this.queue.read(() => {
|
||||||
this.iconVisible = true;
|
this.iconVisible = true;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Component, Element, EventListenerEnable, Listen, Method, Prop, Watch } from '@stencil/core';
|
import { Component, Element, EventListenerEnable, Listen, Method, Prop, Watch } from '@stencil/core';
|
||||||
import { now } from '../../utils/helpers';
|
import { now } from '../../utils/helpers';
|
||||||
import { DomController } from '../../global/dom-controller';
|
import { QueueController } from '../../index';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
tag: 'ion-ripple-effect',
|
tag: 'ion-ripple-effect',
|
||||||
@ -11,7 +11,7 @@ export class RippleEffect {
|
|||||||
private lastClick = -10000;
|
private lastClick = -10000;
|
||||||
@Element() el: HTMLElement;
|
@Element() el: HTMLElement;
|
||||||
|
|
||||||
@Prop({context: 'dom'}) dom: DomController;
|
@Prop({context: 'queue'}) queue: QueueController;
|
||||||
@Prop({context: 'enableListener'}) enableListener: EventListenerEnable;
|
@Prop({context: 'enableListener'}) enableListener: EventListenerEnable;
|
||||||
|
|
||||||
@Prop() tapClick = false;
|
@Prop() tapClick = false;
|
||||||
@ -50,7 +50,7 @@ export class RippleEffect {
|
|||||||
addRipple(pageX: number, pageY: number) {
|
addRipple(pageX: number, pageY: number) {
|
||||||
let x: number, y: number, size: number;
|
let x: number, y: number, size: number;
|
||||||
|
|
||||||
this.dom.read(() => {
|
this.queue.read(() => {
|
||||||
const rect = this.el.getBoundingClientRect();
|
const rect = this.el.getBoundingClientRect();
|
||||||
const width = rect.width;
|
const width = rect.width;
|
||||||
const height = rect.height;
|
const height = rect.height;
|
||||||
@ -58,7 +58,7 @@ export class RippleEffect {
|
|||||||
x = pageX - rect.left - (size / 2);
|
x = pageX - rect.left - (size / 2);
|
||||||
y = pageY - rect.top - (size / 2);
|
y = pageY - rect.top - (size / 2);
|
||||||
});
|
});
|
||||||
this.dom.write(() => {
|
this.queue.write(() => {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.classList.add('ripple-effect');
|
div.classList.add('ripple-effect');
|
||||||
const style = div.style;
|
const style = div.style;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
|
import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
|
||||||
import { Config, DomController } from '../../index';
|
import { Config, QueueController } from '../../index';
|
||||||
import { flattenRouterTree, readRedirects, readRoutes } from './utils/parser';
|
import { flattenRouterTree, readRedirects, readRoutes } from './utils/parser';
|
||||||
import { readNavState, writeNavState } from './utils/dom';
|
import { readNavState, writeNavState } from './utils/dom';
|
||||||
import { chainToPath, generatePath, parsePath, readPath, writePath } from './utils/path';
|
import { chainToPath, generatePath, parsePath, readPath, writePath } from './utils/path';
|
||||||
@ -23,7 +23,7 @@ export class Router {
|
|||||||
@Element() el: HTMLElement;
|
@Element() el: HTMLElement;
|
||||||
|
|
||||||
@Prop({ context: 'config' }) config: Config;
|
@Prop({ context: 'config' }) config: Config;
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'queue' }) queue: QueueController;
|
||||||
|
|
||||||
@Prop() base = '';
|
@Prop() base = '';
|
||||||
@Prop() useHash = true;
|
@Prop() useHash = true;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
|
import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
|
||||||
import { Config, DomController, GestureDetail } from '../../index';
|
import { Config, GestureDetail, QueueController } from '../../index';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
tag: 'ion-scroll',
|
tag: 'ion-scroll',
|
||||||
@ -22,7 +22,7 @@ export class Scroll {
|
|||||||
@Element() private el: HTMLElement;
|
@Element() private el: HTMLElement;
|
||||||
|
|
||||||
@Prop({ context: 'config'}) config: Config;
|
@Prop({ context: 'config'}) config: Config;
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'queue' }) queue: QueueController;
|
||||||
|
|
||||||
@Prop() mode: string;
|
@Prop() mode: string;
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ export class Scroll {
|
|||||||
}
|
}
|
||||||
if (!this.queued && this.scrollEvents) {
|
if (!this.queued && this.scrollEvents) {
|
||||||
this.queued = true;
|
this.queued = true;
|
||||||
this.dom.read(timeStamp => {
|
this.queue.read(timeStamp => {
|
||||||
this.queued = false;
|
this.queued = false;
|
||||||
this.detail.event = ev;
|
this.detail.event = ev;
|
||||||
updateScrollDetail(this.detail, this.el, timeStamp, didStart);
|
updateScrollDetail(this.detail, this.el, timeStamp, didStart);
|
||||||
@ -189,7 +189,7 @@ export class Scroll {
|
|||||||
if (easedT < 1) {
|
if (easedT < 1) {
|
||||||
// do not use DomController here
|
// do not use DomController here
|
||||||
// must use nativeRaf in order to fire in the next frame
|
// must use nativeRaf in order to fire in the next frame
|
||||||
self.dom.raf(step);
|
self.queue.read(step);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
stopScroll = true;
|
stopScroll = true;
|
||||||
@ -203,8 +203,8 @@ export class Scroll {
|
|||||||
self.isScrolling = true;
|
self.isScrolling = true;
|
||||||
|
|
||||||
// chill out for a frame first
|
// chill out for a frame first
|
||||||
this.dom.write(() => {
|
this.queue.write(() => {
|
||||||
this.dom.write(timeStamp => {
|
this.queue.write(timeStamp => {
|
||||||
startTime = timeStamp;
|
startTime = timeStamp;
|
||||||
step(timeStamp);
|
step(timeStamp);
|
||||||
});
|
});
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import { Component, Listen, Prop } from '@stencil/core';
|
import { Component, Listen, Prop } from '@stencil/core';
|
||||||
import { DomController } from '../..';
|
import { QueueController } from '../..';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
tag: 'ion-status-tap'
|
tag: 'ion-status-tap'
|
||||||
})
|
})
|
||||||
export class StatusTap {
|
export class StatusTap {
|
||||||
|
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'queue' }) queue: QueueController;
|
||||||
|
|
||||||
@Prop() duration = 300;
|
@Prop() duration = 300;
|
||||||
|
|
||||||
@Listen('window:statusTap')
|
@Listen('window:statusTap')
|
||||||
onStatusTap() {
|
onStatusTap() {
|
||||||
this.dom.read(() => {
|
this.queue.read(() => {
|
||||||
const width = window.innerWidth;
|
const width = window.innerWidth;
|
||||||
const height = window.innerWidth;
|
const height = window.innerWidth;
|
||||||
const el = document.elementFromPoint(width / 2, height / 2);
|
const el = document.elementFromPoint(width / 2, height / 2);
|
||||||
@ -22,7 +22,7 @@ export class StatusTap {
|
|||||||
const scrollEl = el.closest('ion-scroll');
|
const scrollEl = el.closest('ion-scroll');
|
||||||
if (scrollEl) {
|
if (scrollEl) {
|
||||||
scrollEl.componentOnReady().then(() => {
|
scrollEl.componentOnReady().then(() => {
|
||||||
this.dom.write(() => {
|
this.queue.write(() => {
|
||||||
scrollEl.scrollToTop(this.duration);
|
scrollEl.scrollToTop(this.duration);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Component, Element, Listen, Prop, State, Watch } from '@stencil/core';
|
import { Component, Element, Listen, Prop, State, Watch } from '@stencil/core';
|
||||||
import { createThemedClasses } from '../../utils/theme';
|
import { createThemedClasses } from '../../utils/theme';
|
||||||
import { DomController } from '../../index';
|
import { QueueController } from '../../index';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
tag: 'ion-tabbar',
|
tag: 'ion-tabbar',
|
||||||
@ -23,7 +23,7 @@ export class Tabbar {
|
|||||||
|
|
||||||
@State() hidden = false;
|
@State() hidden = false;
|
||||||
|
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'queue' }) queue: QueueController;
|
||||||
@Prop() placement = 'bottom';
|
@Prop() placement = 'bottom';
|
||||||
@Prop() selectedTab: HTMLIonTabElement;
|
@Prop() selectedTab: HTMLIonTabElement;
|
||||||
@Prop() scrollable: boolean;
|
@Prop() scrollable: boolean;
|
||||||
@ -99,7 +99,7 @@ export class Tabbar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected scrollToSelectedButton() {
|
protected scrollToSelectedButton() {
|
||||||
this.dom.read(() => {
|
this.queue.read(() => {
|
||||||
const activeTabButton = this.getSelectedButton();
|
const activeTabButton = this.getSelectedButton();
|
||||||
|
|
||||||
if (activeTabButton) {
|
if (activeTabButton) {
|
||||||
@ -126,7 +126,7 @@ export class Tabbar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private scrollByTab(direction: 'left' | 'right') {
|
private scrollByTab(direction: 'left' | 'right') {
|
||||||
this.dom.read(() => {
|
this.queue.read(() => {
|
||||||
const {previous, next} = this.analyzeTabs();
|
const {previous, next} = this.analyzeTabs();
|
||||||
const info = direction === 'right' ? next : previous;
|
const info = direction === 'right' ? next : previous;
|
||||||
const amount = info && info.amount;
|
const amount = info && info.amount;
|
||||||
@ -148,7 +148,7 @@ export class Tabbar {
|
|||||||
if (!this.highlight) {
|
if (!this.highlight) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.dom.read(() => {
|
this.queue.read(() => {
|
||||||
const btn = this.getSelectedButton();
|
const btn = this.getSelectedButton();
|
||||||
const highlight = this.el.querySelector('div.tabbar-highlight') as HTMLElement;
|
const highlight = this.el.querySelector('div.tabbar-highlight') as HTMLElement;
|
||||||
if (btn && highlight) {
|
if (btn && highlight) {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { Component, Element, EventListenerEnable, Listen, Method, Prop, Watch } from '@stencil/core';
|
import { Component, Element, EventListenerEnable, Listen, Method, Prop, Watch } from '@stencil/core';
|
||||||
import { DomController } from '../../index';
|
|
||||||
import { Cell, DomRenderFn, HeaderFn, ItemHeightFn,
|
import { Cell, DomRenderFn, HeaderFn, ItemHeightFn,
|
||||||
ItemRenderFn, NodeHeightFn, Range, Viewport,
|
ItemRenderFn, NodeHeightFn, Range, Viewport,
|
||||||
VirtualNode, calcCells, calcHeightIndex, doRender,
|
VirtualNode, calcCells, calcHeightIndex, doRender,
|
||||||
findCellIndex, getRange, getShouldUpdate, getViewport,
|
findCellIndex, getRange, getShouldUpdate, getViewport,
|
||||||
inplaceUpdate, positionForIndex, resizeBuffer, updateVDom } from './virtual-scroll-utils';
|
inplaceUpdate, positionForIndex, resizeBuffer, updateVDom } from './virtual-scroll-utils';
|
||||||
|
import { QueueController } from '../../index';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -30,7 +30,7 @@ export class VirtualScroll {
|
|||||||
|
|
||||||
@Element() el: HTMLStencilElement;
|
@Element() el: HTMLStencilElement;
|
||||||
|
|
||||||
@Prop({context: 'dom'}) dom: DomController;
|
@Prop({context: 'queue'}) queue: QueueController;
|
||||||
@Prop({context: 'enableListener'}) enableListener: EventListenerEnable;
|
@Prop({context: 'enableListener'}) enableListener: EventListenerEnable;
|
||||||
|
|
||||||
|
|
||||||
@ -206,8 +206,8 @@ export class VirtualScroll {
|
|||||||
this.timerUpdate = null;
|
this.timerUpdate = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dom.read(this.readVS.bind(this));
|
this.queue.read(this.readVS.bind(this));
|
||||||
this.dom.read(this.writeVS.bind(this));
|
this.queue.read(this.writeVS.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
private readVS() {
|
private readVS() {
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
/* tslint:disable */
|
|
||||||
export interface Now {
|
|
||||||
(): number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DomController {
|
|
||||||
read: DomControllerCallback;
|
|
||||||
write: DomControllerCallback;
|
|
||||||
raf: DomControllerCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RafCallback {
|
|
||||||
(timeStamp: number): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DomControllerCallback {
|
|
||||||
(cb: RafCallback): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createDomControllerClient(win: Window, now: Now, rafPending?: boolean): DomController {
|
|
||||||
const readCBs: RafCallback[] = [];
|
|
||||||
const writeCBs: RafCallback[] = [];
|
|
||||||
const raf = (cb: FrameRequestCallback): number => win.requestAnimationFrame(cb);
|
|
||||||
|
|
||||||
|
|
||||||
function rafFlush(timeStamp: number, startTime?: number, cb?: RafCallback, err?: any) {
|
|
||||||
try {
|
|
||||||
startTime = now();
|
|
||||||
|
|
||||||
// ******** DOM READS ****************
|
|
||||||
while (cb = readCBs.shift()) {
|
|
||||||
cb(timeStamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ******** DOM WRITES ****************
|
|
||||||
while (cb = writeCBs.shift()) {
|
|
||||||
cb(timeStamp);
|
|
||||||
|
|
||||||
if ((now() - startTime) > 8) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
err = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rafPending = (readCBs.length > 0 || writeCBs.length > 0)) {
|
|
||||||
raf(rafFlush);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
|
|
||||||
read: (cb: RafCallback) => {
|
|
||||||
readCBs.push(cb);
|
|
||||||
|
|
||||||
if (!rafPending) {
|
|
||||||
rafPending = true;
|
|
||||||
raf(rafFlush);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
write: (cb: RafCallback) => {
|
|
||||||
writeCBs.push(cb);
|
|
||||||
|
|
||||||
if (!rafPending) {
|
|
||||||
rafPending = true;
|
|
||||||
raf(rafFlush);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
raf: raf
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,6 +1,5 @@
|
|||||||
import 'ionicons';
|
import 'ionicons';
|
||||||
import { createConfigController } from './config-controller';
|
import { createConfigController } from './config-controller';
|
||||||
import { createDomControllerClient } from './dom-controller';
|
|
||||||
import { PLATFORM_CONFIGS, detectPlatforms, readQueryParam } from './platform-configs';
|
import { PLATFORM_CONFIGS, detectPlatforms, readQueryParam } from './platform-configs';
|
||||||
|
|
||||||
|
|
||||||
@ -8,12 +7,9 @@ const Ionic = (window as any).Ionic = (window as any).Ionic || {};
|
|||||||
|
|
||||||
declare const Context: any;
|
declare const Context: any;
|
||||||
|
|
||||||
// add dom controller, used to coordinate DOM reads and write in order to avoid
|
// queue used to coordinate DOM reads and
|
||||||
// layout thrashing
|
// write in order to avoid layout thrashing
|
||||||
if (!Context.dom) {
|
Ionic.queue = Context.queue;
|
||||||
const now = () => window.performance.now();
|
|
||||||
Context.dom = createDomControllerClient(window, now);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Context.platforms) {
|
if (!Context.platforms) {
|
||||||
Context.platforms = detectPlatforms(window.location.href, window.navigator.userAgent, PLATFORM_CONFIGS, 'core');
|
Context.platforms = detectPlatforms(window.location.href, window.navigator.userAgent, PLATFORM_CONFIGS, 'core');
|
||||||
|
13
core/src/global/queue-controller.ts
Normal file
13
core/src/global/queue-controller.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
export interface QueueController {
|
||||||
|
read: DomControllerCallback;
|
||||||
|
write: DomControllerCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RafCallback {
|
||||||
|
(timeStamp: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DomControllerCallback {
|
||||||
|
(cb: RafCallback): void;
|
||||||
|
}
|
2
core/src/index.d.ts
vendored
2
core/src/index.d.ts
vendored
@ -106,7 +106,7 @@ export { PlatformConfig } from './global/platform-configs';
|
|||||||
// export all of the component declarations that are dynamically created
|
// export all of the component declarations that are dynamically created
|
||||||
export * from './components';
|
export * from './components';
|
||||||
|
|
||||||
export { DomController, RafCallback } from './global/dom-controller';
|
export { QueueController, RafCallback } from './global/queue-controller';
|
||||||
export { FrameworkDelegate } from './utils/framework-delegate';
|
export { FrameworkDelegate } from './utils/framework-delegate';
|
||||||
export { OverlayEventDetail } from './utils/overlays';
|
export { OverlayEventDetail } from './utils/overlays';
|
||||||
export * from './utils/transition';
|
export * from './utils/transition';
|
||||||
|
Reference in New Issue
Block a user