VulpesOS/gaia/apps/system/js/browser_mixin.js
OverSu b38dea0597 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.
2026-09-30 23:13:03 +02:00

356 lines
10 KiB
JavaScript
Executable file

/* global Service */
'use strict';
(function(exports) {
/**
* @mixin BrowserMixin
*/
var BrowserMixin = {
reload: function bm_reload() {
if (this.browser.element) {
this.browser.element.reload();
}
},
/**
* A static timeout to make sure
* the next event don't happen too late.
*/
NEXTPAINT_TIMEOUT: 500,
/**
* Wait for a next paint event from mozbrowser iframe,
* The callback would be called in this.NEXTPAINT_TIMEOUT ms
* if the next paint event doesn't happen.
* The use case is for the moment just before we turn on
* the iframe visibility, so the TIMEOUT isn't too long.
*
* Note: for some reason we intend to use waitForNextPaint now.
*
* @param {Function} callback The callback function to be invoked
* after we get next paint event.
*
* @return {Object} Promise that resolves when the next paint triggers.
* The promise never rejects.
*/
waitForNextPaint: function bm_waitForNextPaint(callback) {
if (!this.browser || !this.browser.element) {
if (callback) {
callback();
}
return;
}
var iframe = this.browser.element;
var nextPaintTimer;
var self = this;
var resolver;
var p = new Promise(function(resolve) {
resolver = resolve;
});
var onNextPaint = function aw_onNextPaint() {
self.debug(' nextpainted.');
iframe.removeNextPaintListener(onNextPaint);
clearTimeout(nextPaintTimer);
resolver();
if (callback) {
callback();
}
};
nextPaintTimer = setTimeout(function ifNextPaintIsTooLate() {
self.debug(' nextpaint is timeouted.');
iframe.removeNextPaintListener(onNextPaint);
resolver();
if (callback) {
callback();
}
}, this.NEXTPAINT_TIMEOUT);
iframe.addNextPaintListener(onNextPaint);
return p;
},
/**
* This function will be called by window managers while top most app
* window is changed to notify nfc module in gecko.
*/
setNFCFocus: function(enable) {
var topWindow = this.getTopMostWindow();
if (!topWindow.browser || !topWindow.browser.element ||
topWindow._nfcActive === enable ||
(topWindow.CLASS_NAME !== 'AppWindow' &&
topWindow.CLASS_NAME !== 'ActivityWindow' &&
topWindow.CLASS_NAME !== 'PopupWindow') &&
topWindow.CLASS_NAME !== 'HomescreenWindow') {
// XXX: Implement this.belongToAppWindow()
return;
}
this.debug(topWindow.name + ':' + topWindow.instanceID +
' is setting nfc active to: ' + enable);
try {
topWindow._nfcActive = enable;
topWindow.browser.element.setNFCFocus(enable);
} catch (err) {
this.debug('set nfc active is not implemented');
}
},
/**
* get the screenshot of mozbrowser iframe.
* If it succeed, the blob would be stored in this._screenshotBlob.
* @param {Function} callback The callback function to be invoked
* after we get the screenshot.
*/
getScreenshot: function bm_getScreenshot(callback, width, height, timeout,
ignoreFront) {
if (!this.browser || !this.browser.element) {
if (callback) {
callback();
}
return;
}
this.debug('getting screenshot..');
var self = this;
var invoked = false;
var timer;
// First, let's check if we have a frontWindow, if so this is the one
// we will want a screenshot of, passing ignoreFront lets us skip this
// if we want a screenshot of the browser element
ignoreFront = (typeof ignoreFront === 'undefined') ? false : ignoreFront;
if (!ignoreFront && this.frontWindow) {
this.frontWindow.getScreenshot(callback, width, height, timeout);
return;
}
if (timeout) {
timer = window.setTimeout(function() {
if (invoked) {
return;
}
self.debug('getScreenshot timeout!');
invoked = true;
callback();
}, timeout);
}
//
// Since homescreen is the only app contains transparent background,
// we only store png screenshot for homescreen to save more memory.
//
var type = this.isHomescreen ?
'image/png' : 'image/jpeg';
var _width = width || this.width ||
Service.query('LayoutManager.width');
var _height = height || this.height ||
Service.query('LayoutManager.height');
this.debug('w=' + _width + ';h=' + _height);
var req = this.iframe.getScreenshot(_width, _height, type);
var success = function(result) {
if (!width) {
// Refresh _screenshotBlob when no width/height is specified.
self.renewCachedScreenshotBlob(result);
}
self.debug('getScreenshot succeed!');
if (invoked) {
return;
}
self.debug('get screenshot success!!!!');
invoked = true;
if (timer) {
window.clearTimeout(timer);
}
if (callback) {
callback(result);
}
};
var error = function() {
self.debug('getScreenshot failed!');
if (invoked) {
return;
}
invoked = true;
if (timer) {
window.clearTimeout(timer);
}
if (callback) {
callback();
}
};
if (req.then) {
req.then(success, error);
} else {
req.onsuccess = function(evt) {
success(evt.target.result);
};
req.onerror = error;
}
},
/**
* For test purpose, we create this method for changing active element. The
* activeElement is readonly property. We may use defineProperty to override
* it. But we get undefined with getOwnPropertyDescriptor. As to
* window.document, it is also a readonly and non-configurable property. We
* cannot override it directly.
*
* @return {HTMLDOMElement} the active element of current document.
*/
getActiveElement: function bm_getActiveElement() {
return document.activeElement;
},
focus: function bm_focus() {
var topWindow = this.getTopMostWindow();
if (topWindow.contextmenu && topWindow.contextmenu.isShown()) {
topWindow.contextmenu.focus();
} else if (topWindow.browser && topWindow.browser.element &&
topWindow.getActiveElement() !== topWindow.browser.element) {
topWindow.browser.element.focus();
}
},
blur: function bm_blur() {
var topWindow = this.getTopMostWindow();
if (topWindow.browser && topWindow.browser.element &&
topWindow.getActiveElement() === topWindow.browser.element) {
topWindow.browser.element.blur();
}
},
back: function bm_back() {
if (this.browser.element) {
this.browser.element.goBack();
}
},
forward: function bm_forward() {
if (this.browser.element) {
this.browser.element.goForward();
}
},
stop: function bm_stop() {
if (this.browser.element) {
this.browser.element.stop();
}
},
_setVisible: function bm__setVisible(visible) {
if (this.browser && this.browser.element &&
'setVisible' in this.browser.element) {
this.debug('setVisible on browser element:' + visible);
this.browser.element.setVisible(visible);
}
},
_setActive: function bm__setActive(active) {
if (this.browser && this.browser.element &&
'setActive' in this.browser.element) {
this.debug('setActive on browser element:' + active);
this.browser.element.setActive(active);
}
},
/**
* Set aria-hidden attribute on browser's element to handle its screen
* reader visibility.
* @type {Boolean} visible A flag indicating if the element should be screen
* reader visible.
*/
_setVisibleForScreenReader:
function bm__setVisibleForScreenReader(visible) {
if (this.browser && this.browser.element) {
this.debug('aria-hidden on browser element:' + !visible);
this.browser.element.setAttribute('aria-hidden', !visible);
}
},
/**
* Fire a DOM Request to detect the history has previous page or not.
* @param {Function} callback Called when DOM Request is done.
*/
canGoBack: function bm_cangoback(callback) {
var self = this;
if (this.browser.element) {
var r = this.browser.element.getCanGoBack();
var success = function(result) {
self._backable = result;
if (callback) {
callback(result);
}
};
var error = function() {
if (callback) {
callback();
}
};
if (r.then) {
r.then(success, error);
} else {
r.onsuccess = function(evt) {
success(evt.target.result);
};
r.onerror = error;
}
} else {
if (callback) {
callback();
}
}
},
/**
* Fire a DOM Request to detect the history has next page or not.
* @param {Function} callback Called when DOM Request is done.
*/
canGoForward: function bm_cangoforward(callback) {
var self = this;
if (this.browser.element) {
var r = this.browser.element.getCanGoForward();
var success = function(result) {
self._forwardable = result;
if (callback) {
callback(result);
}
};
var error = function() {
if (callback) {
callback();
}
};
if (r.then) {
r.then(success, error);
} else {
r.onsuccess = function(evt) {
success(evt.target.result);
};
r.onerror = error;
}
} else {
if (callback) {
callback();
}
}
},
/**
* Decide we are in out of process or not.
*/
isOOP: function bm_isOOP() {
return (this.browser_config && this.browser_config.oop);
}
};
if (exports.AppWindow) {
exports.AppWindow.addMixin(BrowserMixin);
}
}(window));