Files
2017-06-14 22:45:01 -05:00

173 lines
4.7 KiB
TypeScript

import { Config } from '../../../config/config';
import { DomController } from '../../../platform/dom-controller';
import { NgZone } from '@angular/core';
import { Platform } from '../../../platform/platform';
/**
* @hidden
*/
export function setupCore(config: Config, plt: Platform, domCtrl: DomController, zone: NgZone) {
return function() {
const win: any = plt.win();
const doc = plt.doc();
const ionic: any = win['Ionic'];
if (!ionic || !ionic['staticDir']) {
// window.Ionic should already exist and
// window.Ionic.staticDir should have been added to the
// main bundle referencing the static www build directory
return;
}
// same controllers are used by ionic core
ionic['ConfigCtrl'] = config;
// keep core and angular dom reads/writes *nsync
ionic['DomCtrl'] = domCtrl;
// next tick controller created here so that it can
// be created to run outside of angular
ionic['QueueCtrl'] = getQueueController(win, zone);
// keep core and angular dom reads/writes *nsync
ionic['eventNameFn'] = function(eventName: string) {
return '$' + eventName;
};
// build up a path for the exact ionic core javascript file this browser needs
var pathItems: string[] = ['core'];
if (!('attachShadow' in Element.prototype)) {
// browser requires the shadow dom polyfill
pathItems.push('sd');
}
if (!win.customElements) {
// browser requires the custom elements polyfill
pathItems.push('ce');
}
// request the ionic core file this browser needs
var s = doc.createElement('script');
s.src = `${ionic['staticDir']}ionic.${pathItems.join('.')}.js`;
doc.head.appendChild(s);
return {};
};
}
function getQueueController(win: any, zone: NgZone) {
function now() {
return win.performance.now();
}
const highPromise = Promise.resolve();
const highCallbacks: Function[] = [];
const mediumCallbacks: Function[] = [];
const lowCallbacks: Function[] = [];
let resolvePending = false;
let ricPending = false;
function doHighPriority() {
// holy geez we need to get this stuff done and fast
// all high priority callbacks should be fired off immediately
while (highCallbacks.length > 0) {
highCallbacks.shift()();
}
resolvePending = false;
}
function doWork() {
const start = now();
// always run all of the high priority work if there is any
doHighPriority();
while (mediumCallbacks.length > 0 && (now() - start < 40)) {
mediumCallbacks.shift()();
}
if (mediumCallbacks.length === 0) {
// we successfully drained the medium queue or the medium queue is empty
// so now let's drain the low queue with our remaining time
while (lowCallbacks.length > 0 && (now() - start < 40)) {
lowCallbacks.shift()();
}
}
// check to see if we still have work to do
if (ricPending = (mediumCallbacks.length > 0 || lowCallbacks.length > 0)) {
// everyone just settle down now
// we already don't have time to do anything in this callback
// let's throw the next one in a requestAnimationFrame
// so we can just simmer down for a bit
zone.runOutsideAngular(() => {
win.requestAnimationFrame(flush);
});
}
}
function flush() {
// always run all of the high priority work if there is any
doHighPriority();
// always force a bunch of medium callbacks to run, but still have
// a throttle on how many can run in a certain time
const start = now();
while (mediumCallbacks.length > 0 && (now() - start < 4)) {
mediumCallbacks.shift()();
}
if (ricPending = (mediumCallbacks.length > 0 || lowCallbacks.length > 0)) {
// still more to do yet, but we've run out of time
// let's let this thing cool off and try again in the next ric
zone.runOutsideAngular(() => {
win.requestAnimationFrame(doWork);
});
}
}
function add(cb: Function, priority?: number) {
if (priority === 3) {
// uses Promise.resolve() for next tick
highCallbacks.push(cb);
if (!resolvePending) {
// not already pending work to do, so let's tee it up
resolvePending = true;
highPromise.then(doHighPriority);
}
} else {
if (priority === 1) {
lowCallbacks.push(cb);
} else {
// defaults to medium priority
// uses requestIdleCallback
mediumCallbacks.push(cb);
}
if (!ricPending) {
// not already pending work to do, so let's tee it up
ricPending = true;
zone.runOutsideAngular(() => {
win.requestAnimationFrame(doWork);
});
}
}
}
return {
add: add,
flush: flush
};
}