Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
588
gaia/apps/system/js/input_window_manager.js
Executable file
588
gaia/apps/system/js/input_window_manager.js
Executable file
|
|
@ -0,0 +1,588 @@
|
|||
'use strict';
|
||||
|
||||
/* global applications, InputWindow, SettingsListener, KeyboardManager,
|
||||
Service, Promise */
|
||||
|
||||
(function(exports) {
|
||||
|
||||
/**
|
||||
* For some flow diagrams related to input management, please refer to
|
||||
* https://wiki.mozilla.org/Gaia/System/InputManagement#Flow_Diagrams .
|
||||
*
|
||||
* InputWindowManager manages all the InputWindow-related operations. It shows
|
||||
* /hides/preloads/kills InputWindows for KeyboardManager as specified by
|
||||
* keyboard layouts, and internally book-keeps those InputWindows and the
|
||||
* currently displayed one.
|
||||
*
|
||||
* An input app may specify different layouts. A layout passed from
|
||||
* KeyboardManager may specify its manifestURL (mapping to the input app), and
|
||||
* its path (i.e. the Input Window frame src).
|
||||
*
|
||||
* The path is like: /index.html#en. Different layouts of the same input app
|
||||
* may differ in only the hash part of the path, or may differ in the whole
|
||||
* path.
|
||||
*
|
||||
* Currently, when we are to display a keyboard layout, we may reuse
|
||||
* an InputWindow of the same (manifestURL, path_without_hash) of that layout,
|
||||
* and only replaces the hash part of the src of that InputWindow frame.
|
||||
* To say it another way, We have different InputWindows for different
|
||||
* (manifestURL, path_without_hash) of different layouts.
|
||||
*
|
||||
*
|
||||
* There are several scenarios to be considered when we show a layout:
|
||||
*
|
||||
* - There is currently no displayed InputWindow:
|
||||
* We show the InputWindow for that layout, with animation.
|
||||
*
|
||||
* - There is currently a displayed InputWindow, and we can reuse it for that
|
||||
* layout:
|
||||
* InputWindow will know to change its hash only, and does not re-animate
|
||||
* for showing.
|
||||
*
|
||||
* - There is currently a displayed InputWindow, and it is closing, and we'll
|
||||
* re-use it:
|
||||
* InputWindow will know to show itself without animation (and may change)
|
||||
* its frame src hash)
|
||||
*
|
||||
* - There is currently a displayed InputWindow, and we can't re-use it:
|
||||
* We show the new InputWindow without animation, and hide the old
|
||||
* InputWindow, without animation, when the new InputWIndow is ready.
|
||||
*/
|
||||
var InputWindowManager = function() {
|
||||
this.isOutOfProcessEnabled = false;
|
||||
this._totalMemory = 0;
|
||||
|
||||
this._getMemory();
|
||||
|
||||
this._oopSettingCallbackBind = null;
|
||||
|
||||
/*
|
||||
* The collection of loaded InputWindows.
|
||||
* This is a two-level map, from input app manifestURL to path_without_hash
|
||||
* to an InputWindow. By this structure we fulfill the need to reuse
|
||||
* an InputWindow for the same (manifestURL, path_without_hash) of layouts
|
||||
* as said above.
|
||||
*
|
||||
* {
|
||||
* 'keyboard.gaiamobile.org/manifest.webapp' : {
|
||||
* '/index.html': inputWindow1,
|
||||
* '/complex.html': inputWindow2,
|
||||
* },
|
||||
* 'demo-keyboard.gaiamobile.org/manifest.webapp' : {
|
||||
* '/ime1.html': inputWindow3,
|
||||
* '/ime2.html': inputWindow4,
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*/
|
||||
this._inputWindows = {};
|
||||
|
||||
// The InputWindow that's being displayed
|
||||
this._currentWindow = null;
|
||||
|
||||
// This points to an InputWindow that should be closed but displayed during
|
||||
// the timeout.
|
||||
this._windowToClose = null;
|
||||
|
||||
// The switched-out InputWindow that we need to deactivate when the
|
||||
// switched-in InputWindow finishes activation.
|
||||
this._lastWindow = null;
|
||||
|
||||
this._onDebug = false;
|
||||
};
|
||||
|
||||
InputWindowManager.prototype.name = 'InputWindowManager';
|
||||
|
||||
InputWindowManager.prototype._debug = function iwm__debug(msg) {
|
||||
if (this._onDebug) {
|
||||
console.log('[InputWindowManager] ' + msg);
|
||||
}
|
||||
};
|
||||
|
||||
InputWindowManager.prototype.start = function iwm_start() {
|
||||
// 3rd-party keyboard apps must be run out-of-process.
|
||||
this._oopSettingCallbackBind = this._oopSettingCallback.bind(this);
|
||||
SettingsListener.observe('keyboard.3rd-party-app.enabled', true,
|
||||
this._oopSettingCallbackBind);
|
||||
|
||||
window.addEventListener('input-appopened', this);
|
||||
window.addEventListener('input-appclosed', this);
|
||||
window.addEventListener('input-apprequestclose', this);
|
||||
window.addEventListener('input-appready', this);
|
||||
window.addEventListener('input-appheightchanged', this);
|
||||
window.addEventListener('input-appterminated', this);
|
||||
// For Bug 812115: hide the keyboard when the app is closed here,
|
||||
// since it would take a longer round-trip to receive focuschange
|
||||
// Also in Bug 856692 we realise that we need to close the keyboard
|
||||
// when an inline activity goes away.
|
||||
window.addEventListener('actionmenuopening', this);
|
||||
window.addEventListener('actionmenuhide', this);
|
||||
window.addEventListener('activityrequesting', this);
|
||||
window.addEventListener('activitycanceled', this);
|
||||
window.addEventListener('activitychoosen', this);
|
||||
window.addEventListener('activityopening', this);
|
||||
window.addEventListener('activityclosing', this);
|
||||
window.addEventListener('attentionrequestopen', this);
|
||||
window.addEventListener('attentionrecovering', this);
|
||||
window.addEventListener('attentionopening', this);
|
||||
window.addEventListener('attentionopened', this);
|
||||
window.addEventListener('attentionclosing', this);
|
||||
window.addEventListener('attentionclosed', this);
|
||||
window.addEventListener('notification-clicked', this);
|
||||
window.addEventListener('applicationsetupdialogshow', this);
|
||||
window.addEventListener('sheets-gesture-begin', this);
|
||||
window.addEventListener('cardviewprepare', this);
|
||||
window.addEventListener('lockscreen-appopened', this);
|
||||
window.addEventListener('mozmemorypressure', this);
|
||||
Service.registerState('getHeight', this);
|
||||
Service.registerState('isOutOfProcessEnabled', this);
|
||||
Service.register('hideInputWindow', this);
|
||||
Service.register('hideInputWindowImmediately', this);
|
||||
};
|
||||
|
||||
InputWindowManager.prototype.stop = function iwm_stop() {
|
||||
SettingsListener.unobserve('keyboard.3rd-party-app.enabled',
|
||||
this._oopSettingCallbackBind);
|
||||
this._oopSettingCallbackBind = null;
|
||||
|
||||
window.removeEventListener('input-appopened', this);
|
||||
window.removeEventListener('input-appclosed', this);
|
||||
window.removeEventListener('input-apprequestclose', this);
|
||||
window.removeEventListener('input-appready', this);
|
||||
window.removeEventListener('input-appheightchanged', this);
|
||||
window.removeEventListener('input-appterminated', this);
|
||||
window.removeEventListener('activityopening', this);
|
||||
window.removeEventListener('activityclosing', this);
|
||||
window.removeEventListener('attentionrequestopen', this);
|
||||
window.removeEventListener('attentionrecovering', this);
|
||||
window.removeEventListener('attentionopening', this);
|
||||
window.removeEventListener('attentionopened', this);
|
||||
window.removeEventListener('attentionclosing', this);
|
||||
window.removeEventListener('attentionclosed', this);
|
||||
window.removeEventListener('notification-clicked', this);
|
||||
window.removeEventListener('applicationsetupdialogshow', this);
|
||||
window.removeEventListener('sheets-gesture-begin', this);
|
||||
window.removeEventListener('cardviewprepare', this);
|
||||
window.removeEventListener('lockscreen-appopened', this);
|
||||
window.removeEventListener('mozmemorypressure', this);
|
||||
};
|
||||
|
||||
InputWindowManager.prototype.handleEvent = function iwm_handleEvent(evt) {
|
||||
var inputWindow;
|
||||
var manifestURL;
|
||||
if (evt.type.startsWith('input-app')) {
|
||||
inputWindow = evt.detail;
|
||||
}
|
||||
this._debug('handleEvent: ' + evt.type);
|
||||
switch (evt.type) {
|
||||
case 'input-appopened':
|
||||
case 'input-appheightchanged':
|
||||
// for opened/ready/heightchanged events, make sure the originating
|
||||
// InputWindow is the displayed one
|
||||
if (inputWindow === this._currentWindow) {
|
||||
this._kbPublish('keyboardchange', inputWindow.height);
|
||||
}
|
||||
break;
|
||||
case 'input-appready':
|
||||
if (inputWindow === this._currentWindow) {
|
||||
KeyboardManager._onKeyboardReady();
|
||||
}
|
||||
// don't bother close the last window if it's been killed
|
||||
// (happens when last window was replaced due to OOM-kill)
|
||||
if (this._lastWindow) {
|
||||
if (!this._lastWindow.isDead()) {
|
||||
this._lastWindow.close('immediate');
|
||||
}
|
||||
this._lastWindow = null;
|
||||
}
|
||||
break;
|
||||
case 'input-appclosed':
|
||||
// bug 1112416: when blur and focus successively fire, there is a racing
|
||||
// where we may close an inputWindow while its input app is still busy
|
||||
// to become ready. If we were to set that inputWindow as inactive
|
||||
// input, it would abort that input app's becoming-ready progress and
|
||||
// we'll get stuck. Thus, do not really set the inactiveness when we
|
||||
// know the inputWindow is waiting to be ready.
|
||||
this._debug('inputWindow pendingReady: ' + inputWindow._pendingReady);
|
||||
|
||||
if (inputWindow._pendingReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputWindow._setAsActiveInput(false);
|
||||
if (!this._currentWindow) {
|
||||
this._kbPublish('keyboardhidden', undefined);
|
||||
}
|
||||
break;
|
||||
case 'input-appterminated':
|
||||
// input app is OOM-killed...
|
||||
manifestURL = inputWindow.manifestURL;
|
||||
|
||||
// We always destroy the reference of all current InputWindows for that
|
||||
// input app.
|
||||
this._removeInputApp(manifestURL);
|
||||
|
||||
// if the showing window is the killed window,
|
||||
// we need to notify KeyboardManager to relaunch something.
|
||||
if (this._currentWindow &&
|
||||
this._currentWindow.manifestURL === manifestURL) {
|
||||
KeyboardManager._onKeyboardKilled(manifestURL);
|
||||
}
|
||||
break;
|
||||
|
||||
// We want to avoid the keyboard showing while opening
|
||||
// an actionmenu/attention. These are the event
|
||||
// pairs:
|
||||
// actionmenuopening - actionmenuhide
|
||||
// attentionopening - attentionopened
|
||||
// activityrequesting - activitycanceled/activitychoosen
|
||||
case 'actionmenuopening':
|
||||
case 'attentionopening':
|
||||
case 'activityrequesting':
|
||||
this.blockInput = true;
|
||||
this.hideInputWindowImmediately();
|
||||
navigator.mozInputMethod.removeFocus();
|
||||
break;
|
||||
case 'actionmenuhide':
|
||||
case 'activityclosing':
|
||||
case 'activitychoosen':
|
||||
case 'activitycanceled':
|
||||
case 'attentionrequestopen':
|
||||
case 'attentionrecovering':
|
||||
case 'activityopening':
|
||||
case 'attentionclosing':
|
||||
case 'attentionopened':
|
||||
case 'attentionclosed':
|
||||
case 'notification-clicked':
|
||||
case 'applicationsetupdialogshow':
|
||||
this.blockInput = false;
|
||||
this.hideInputWindowImmediately();
|
||||
|
||||
// Ensure the actual focus is lost too in case the dispatcher of
|
||||
// these events didn't remove the focus.
|
||||
navigator.mozInputMethod.removeFocus();
|
||||
|
||||
break;
|
||||
case 'lockscreen-appopened':
|
||||
case 'sheets-gesture-begin':
|
||||
case 'cardviewprepare':
|
||||
if (this._hasActiveInputApp()) {
|
||||
// Instead of hideInputWindow(), we should removeFocus() here.
|
||||
// (and removing the focus cause Gecko to ask us to hideInputWindow())
|
||||
|
||||
// We need to blur the app to prevent the keyboard from refocusing
|
||||
// right away.
|
||||
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1138977
|
||||
var app = Service.query('getTopMostWindow');
|
||||
app && app.blur();
|
||||
navigator.mozInputMethod.removeFocus();
|
||||
}
|
||||
break;
|
||||
case 'mozmemorypressure':
|
||||
// Memory pressure event. If input apps are loaded but not active,
|
||||
// get rid of them.
|
||||
// We only do that when we don't run input apps OOP.
|
||||
this._debug('mozmemorypressure event');
|
||||
if (!this.isOutOfProcessEnabled && !this._hasActiveInputApp()) {
|
||||
this.getLoadedManifestURLs().forEach(manifestURL => {
|
||||
this._removeInputApp(manifestURL);
|
||||
});
|
||||
this._debug('mozmemorypressure event; keyboards removed');
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
InputWindowManager.prototype._getMemory = function iwm_getMemory() {
|
||||
Service.request('getDeviceMemory').then((mem) => {
|
||||
this._totalMemory = mem;
|
||||
});
|
||||
};
|
||||
|
||||
InputWindowManager.prototype._oopSettingCallback =
|
||||
function iwm_oopSettingCallback(value) {
|
||||
this.isOutOfProcessEnabled = value;
|
||||
};
|
||||
|
||||
// returns true if the currentWindow is being removed
|
||||
// we can't use Array.prototype.every() or some() because we'll anyway have
|
||||
// to loop through the whole array
|
||||
InputWindowManager.prototype._onInputLayoutsRemoved =
|
||||
function iwm_onInputLayoutsRemoved(manifestURLs) {
|
||||
var currentWindowRemoved = false;
|
||||
|
||||
manifestURLs.forEach(manifestURL => {
|
||||
if (this._currentWindow &&
|
||||
this._currentWindow.manifestURL === manifestURL) {
|
||||
this.hideInputWindow();
|
||||
currentWindowRemoved = true;
|
||||
}
|
||||
this._removeInputApp(manifestURL);
|
||||
});
|
||||
|
||||
return currentWindowRemoved;
|
||||
};
|
||||
|
||||
InputWindowManager.prototype._removeInputApp =
|
||||
function iwm_removeInputApp(manifestURL) {
|
||||
if (!this._inputWindows[manifestURL]) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var pathInitial in this._inputWindows[manifestURL]) {
|
||||
this._inputWindows[manifestURL][pathInitial].destroy();
|
||||
delete this._inputWindows[manifestURL][pathInitial];
|
||||
}
|
||||
|
||||
delete this._inputWindows[manifestURL];
|
||||
};
|
||||
|
||||
InputWindowManager.prototype.getHeight = function iwm_getHeight() {
|
||||
return this._currentWindow ? this._currentWindow.height : 0;
|
||||
};
|
||||
|
||||
InputWindowManager.prototype._hasActiveInputApp =
|
||||
function iwm_hasActiveInputApp() {
|
||||
return !!this._currentWindow;
|
||||
};
|
||||
|
||||
// Extract some re-usable configs from the layout
|
||||
// pathInitial is |path| without the hash part
|
||||
// hash is the hash part of the |path|, including #, may be empty string
|
||||
// XXX: this should be done at KeyboardManager or KeyboardHelper
|
||||
// when we normalize the layouts there
|
||||
InputWindowManager.prototype._extractLayoutConfigs =
|
||||
function iwm_extractLayoutConfigs(layout){
|
||||
var manifestURL = layout.manifestURL;
|
||||
var path = layout.path;
|
||||
var id = layout.id;
|
||||
var origin = layout.origin;
|
||||
|
||||
var pathInitial;
|
||||
var hash;
|
||||
if (path.indexOf('#') === -1) {
|
||||
pathInitial = path;
|
||||
hash = '';
|
||||
} else {
|
||||
pathInitial = path.substring(0, path.indexOf('#'));
|
||||
hash = path.substring(path.indexOf('#'));
|
||||
}
|
||||
|
||||
var app = applications.getByManifestURL(manifestURL);
|
||||
|
||||
return {
|
||||
manifest: app.manifest,
|
||||
manifestURL: manifestURL,
|
||||
path: path,
|
||||
id: id,
|
||||
pathInitial: pathInitial,
|
||||
hash: hash,
|
||||
origin: origin
|
||||
};
|
||||
};
|
||||
|
||||
InputWindowManager.prototype._makeInputWindow =
|
||||
function iwm_makeInputWindow(configs){
|
||||
var isCertifiedApp = (configs.manifest.type === 'certified');
|
||||
|
||||
if (0 === this._totalMemory){
|
||||
console.warn('InputWindowManager: totalMemory is 0');
|
||||
}
|
||||
|
||||
// oop is always enabled for non-certified app,
|
||||
// and optionally enabled to certified apps if
|
||||
// available memory is more than 512MB.
|
||||
if (this.isOutOfProcessEnabled &&
|
||||
(!isCertifiedApp || this._totalMemory >= 512)) {
|
||||
this._debug('=== Enable keyboard: ' +
|
||||
configs.origin + ' run as OOP ===');
|
||||
configs.oop = true;
|
||||
} else {
|
||||
configs.oop = false;
|
||||
}
|
||||
|
||||
var inputWindow = new InputWindow(configs);
|
||||
|
||||
this._inputWindows[configs.manifestURL] =
|
||||
this._inputWindows[configs.manifestURL] || {};
|
||||
|
||||
this._inputWindows[configs.manifestURL][configs.pathInitial] =
|
||||
inputWindow;
|
||||
|
||||
return inputWindow;
|
||||
};
|
||||
|
||||
InputWindowManager.prototype.preloadInputWindow =
|
||||
function iwm_preloadInputWindow(layout) {
|
||||
var configs = this._extractLayoutConfigs(layout);
|
||||
configs.stayBackground = true;
|
||||
this._makeInputWindow(configs);
|
||||
};
|
||||
|
||||
InputWindowManager.prototype.showInputWindow =
|
||||
function iwm_showInputWindow(layout) {
|
||||
if (this.blockInput) {
|
||||
navigator.mozInputMethod.removeFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
var configs = this._extractLayoutConfigs(layout);
|
||||
|
||||
// see if we can reuse an InputWindow...
|
||||
var nextWindow =
|
||||
this._inputWindows[configs.manifestURL] ?
|
||||
this._inputWindows[configs.manifestURL][configs.pathInitial] :
|
||||
undefined;
|
||||
|
||||
if (!nextWindow){
|
||||
// no, we can't reuse. make a new one.
|
||||
nextWindow = this._makeInputWindow(configs);
|
||||
}
|
||||
|
||||
if (this._currentWindow && nextWindow !== this._currentWindow) {
|
||||
// we have some displayed InputWindow and the new window is a different IW
|
||||
// let the new one show immediately, and this._lastWindow will also be
|
||||
// closed immediately after the new one is ready
|
||||
this._lastWindow = this._currentWindow;
|
||||
configs.immediateOpen = true;
|
||||
nextWindow.open(configs);
|
||||
} else {
|
||||
// we don't have any displayed InputWindow, or the currently displayed
|
||||
// one is what we'd like to open, so just show it normally.
|
||||
nextWindow.open(configs);
|
||||
}
|
||||
|
||||
this._currentWindow = nextWindow;
|
||||
};
|
||||
|
||||
InputWindowManager.prototype.HIDE_INPUT_WINDOW_TIMEOUT = 200;
|
||||
|
||||
InputWindowManager.prototype.hideInputWindow =
|
||||
function iwm_hideInputWindow() {
|
||||
if (!this._currentWindow){
|
||||
return;
|
||||
}
|
||||
|
||||
var windowToClose = this._windowToClose = this._currentWindow;
|
||||
this._currentWindow = null;
|
||||
|
||||
// If the focus is regain within a short time, we would not want to resize
|
||||
// the forground app viewport, which creates suboptimal experiences
|
||||
// (see bug 1176926 and bug 1176771).
|
||||
//
|
||||
// Previously we tried to remove this timeout by delay the blurring message
|
||||
// with a next tick from forms.js (bug 1057898), but this is suboptimal
|
||||
// for the following reasons: While the focus is regain before next tick
|
||||
// when switching between two inputs (see the case in bug 1057898),
|
||||
// That will not work when the focus is removed by tapping a button and
|
||||
// regain at the click event of the button (which is the case of Message app
|
||||
// composer). In this case, the focus is removed at mousedown/touchstart
|
||||
// event; next tick of the blur would happen *before* touchend and click
|
||||
// events of the button.
|
||||
//
|
||||
// This timeout also happen to absorb the event order differences between
|
||||
// oop/inproc environment (see bug 1171950 comment 2).
|
||||
return new Promise(function(resolve) {
|
||||
setTimeout(resolve, this.HIDE_INPUT_WINDOW_TIMEOUT);
|
||||
}.bind(this))
|
||||
.then(function iwm_publishKeyboardHideEventSync() {
|
||||
// We should not close ourselves if we are being set back to become
|
||||
// the currentWindow again, which implies we have already regain the
|
||||
// focus.
|
||||
if (this._currentWindow === windowToClose) {
|
||||
this._windowToClose = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// We also should abort if _windowToClose is already null, indicating
|
||||
// the keyboardhide event is already dispatched.
|
||||
if (this._windowToClose === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set this flag to null so that keyboardhide event will not be
|
||||
// dispatched again in another call.
|
||||
this._windowToClose = null;
|
||||
|
||||
// Publish an keyboardhide event that would cause the
|
||||
// foreground app to resize.
|
||||
// The promise will resolve when all the promises passed to waitUntil()
|
||||
// have resolved.
|
||||
return this._kbPublish('keyboardhide', undefined);
|
||||
}.bind(this))
|
||||
.then(function iwm_hideInputWindowSync() {
|
||||
// We should not close ourselves if we are being set back to become
|
||||
// the currentWindow again.
|
||||
if (this._currentWindow === windowToClose) {
|
||||
return;
|
||||
}
|
||||
|
||||
windowToClose.close();
|
||||
}.bind(this))
|
||||
.catch((e) => { console.error(e); });
|
||||
};
|
||||
|
||||
InputWindowManager.prototype.hideInputWindowImmediately =
|
||||
function iwm_hideInputWindowImmediately() {
|
||||
if (!this._currentWindow && !this._windowToClose){
|
||||
return;
|
||||
}
|
||||
|
||||
this._kbPublish('keyboardhide', undefined);
|
||||
|
||||
var windowToClose = this._currentWindow || this._windowToClose;
|
||||
this._currentWindow = this._windowToClose = null;
|
||||
windowToClose.close('immediate');
|
||||
};
|
||||
|
||||
InputWindowManager.prototype.getLoadedManifestURLs =
|
||||
function iwm_getLoadedManifestURLs() {
|
||||
return Object.keys(this._inputWindows);
|
||||
};
|
||||
|
||||
// As per bug 952441, we want to use a special way to broadcast system-wide
|
||||
// keyboard-related events
|
||||
// This function returns a promise and it will only resolves when all
|
||||
// promises passed into evt.detail.waitUntil() is resolved.
|
||||
InputWindowManager.prototype._kbPublish =
|
||||
function iwm_kbPublish(type, height) {
|
||||
var chainedPromise = Promise.resolve();
|
||||
var returned = false;
|
||||
|
||||
var eventInitDict = {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
detail: {
|
||||
height: height,
|
||||
waitUntil: function(p) {
|
||||
// Need an extra protection here since waitUntil will be an no-op
|
||||
// when chainedPromise is already returned.
|
||||
if (returned) {
|
||||
throw new Error('InputWindowManager: You must call waitUntil()' +
|
||||
' within the event handling loop.');
|
||||
}
|
||||
|
||||
// No point to put it into the queue if it's not a then-able.
|
||||
if (!p || typeof p.then !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
chainedPromise = chainedPromise
|
||||
.then(function() { return p; })
|
||||
.catch((e) => { console.error(e); });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// We dispatch the events at the body level so we are able to intercept
|
||||
// them and prevent page resizing where desired.
|
||||
var evt = new CustomEvent(type, eventInitDict);
|
||||
document.body.dispatchEvent(evt);
|
||||
|
||||
returned = true;
|
||||
return chainedPromise;
|
||||
};
|
||||
|
||||
exports.InputWindowManager = InputWindowManager;
|
||||
|
||||
})(window);
|
||||
Loading…
Reference in a new issue