[IMP] mail: add browser key to messaging

closes odoo/odoo#83854

Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
tsm-odoo
2022-02-03 17:59:46 +00:00
parent 496c0f0d47
commit dc7d71823d
14 changed files with 83 additions and 70 deletions
@@ -17,7 +17,7 @@ export class NotificationAlert extends Component {
if (!this.messaging) {
return false;
}
const windowNotification = this.env.browser.Notification;
const windowNotification = this.messaging.browser.Notification;
return (
windowNotification &&
windowNotification.permission !== "granted" &&
@@ -49,7 +49,7 @@ export class NotificationRequest extends Component {
* @private
*/
_onClick() {
const windowNotification = this.env.browser.Notification;
const windowNotification = this.messaging.browser.Notification;
const def = windowNotification && windowNotification.requestPermission();
if (def) {
def.then(this._handleResponseNotificationPermission.bind(this));
@@ -231,7 +231,7 @@ registerModel({
*/
_prepareAttachmentsLoading() {
this._isPreparingAttachmentsLoading = true;
this._attachmentsLoaderTimeout = this.env.browser.setTimeout(() => {
this._attachmentsLoaderTimeout = this.messaging.browser.setTimeout(() => {
this.update({ isShowingAttachmentsLoading: true });
this._isPreparingAttachmentsLoading = false;
}, this.messaging.loadingBaseDelayDuration);
@@ -240,7 +240,7 @@ registerModel({
* @private
*/
_stopAttachmentsLoading() {
this.env.browser.clearTimeout(this._attachmentsLoaderTimeout);
this.messaging.browser.clearTimeout(this._attachmentsLoaderTimeout);
this._attachmentsLoaderTimeout = null;
this._isPreparingAttachmentsLoading = false;
},
@@ -197,7 +197,7 @@ registerModel({
return;
}
// Let event be handled by bubbling handlers first
await new Promise(this.env.browser.setTimeout);
await new Promise(this.messaging.browser.setTimeout);
if (isEventHandled(ev, 'MessageActionList.replyTo')) {
return;
}
@@ -2,6 +2,7 @@
import { registerModel } from '@mail/model/model_core';
import { attr } from '@mail/model/model_field';
import { browser } from "@web/core/browser/browser";
registerModel({
name: 'Device',
@@ -12,7 +13,7 @@ registerModel({
this._onResize = _.debounce(() => this._refresh(), 100);
},
_willDelete() {
window.removeEventListener('resize', this._onResize);
browser.removeEventListener('resize', this._onResize);
},
},
recordMethods: {
@@ -20,17 +21,15 @@ registerModel({
* Called when messaging is started.
*/
start() {
// TODO FIXME Not using this.env.browser because it's proxified, and
// addEventListener does not work on proxified window. task-2234596
window.addEventListener('resize', this._onResize);
browser.addEventListener('resize', this._onResize);
},
/**
* @private
*/
_refresh() {
this.update({
globalWindowInnerHeight: this.env.browser.innerHeight,
globalWindowInnerWidth: this.env.browser.innerWidth,
globalWindowInnerHeight: this.messaging.browser.innerHeight,
globalWindowInnerWidth: this.messaging.browser.innerWidth,
isMobile: this.env.device.isMobile,
isMobileDevice: this.messaging.device.isMobileDevice,
sizeClass: this.env.device.size_class,
@@ -145,7 +145,7 @@ registerModel({
return;
}
try {
const response = await this.env.browser.fetch('/mail/attachment/upload', {
const response = await this.messaging.browser.fetch('/mail/attachment/upload', {
method: 'POST',
body: this._createFormData({ composer, file, thread }),
signal: uploadingAttachment.uploadingAbortController.signal,
@@ -13,10 +13,10 @@ registerModel({
* Briefly highlights the message.
*/
highlight() {
this.env.browser.clearTimeout(this.highlightTimeout);
this.messaging.browser.clearTimeout(this.highlightTimeout);
this.update({
isHighlighted: true,
highlightTimeout: this.env.browser.setTimeout(() => {
highlightTimeout: this.messaging.browser.setTimeout(() => {
if (!this.exists()) {
return;
}
@@ -155,6 +155,13 @@ registerModel({
}
this.userSetting.update({ rtcLayout: 'sidebar' });
},
/**
* @private
* @returns {Object} browser
*/
_computeBrowser() {
return this.env.browser;
},
/**
* @private
* @returns {Promise}
@@ -184,7 +191,7 @@ registerModel({
* @returns {boolean}
*/
_computeIsNotificationPermissionDefault() {
const browserNotification = this.env.browser.Notification;
const browserNotification = this.messaging.browser.Notification;
return browserNotification ? browserNotification.permission === 'default' : false;
},
/**
@@ -229,6 +236,9 @@ registerModel({
autofetchPartnerImStatus: attr({
default: true,
}),
browser: attr({
compute: '_computeBrowser',
}),
cannedResponses: many('CannedResponse'),
chatWindowManager: one('ChatWindowManager', {
default: insertAndReplace(),
@@ -23,7 +23,7 @@ registerModel({
name: 'Thread',
identifyingFields: ['model', 'id'],
lifecycleHooks: {
_willCreate() {
_created() {
/**
* Timer of current partner that was currently typing something, but
* there is no change on the input for 5 seconds. This is used
@@ -32,7 +32,7 @@ registerModel({
* on the composer for some time.
*/
this._currentPartnerInactiveTypingTimer = new Timer(
this.env,
this.messaging,
() => this.async(() => {
if (this.messaging.currentPartner) {
return this._onCurrentPartnerInactiveTypingTimeout();
@@ -65,7 +65,7 @@ registerModel({
* has stopped typing something.
*/
this._currentPartnerLongTypingTimer = new Timer(
this.env,
this.messaging,
() => this.async(() => this._onCurrentPartnerLongTypingTimeout()),
50 * 1000
);
@@ -102,7 +102,7 @@ registerModel({
* @see _notifyCurrentPartnerTypingStatus
*/
this._throttleNotifyCurrentPartnerTypingStatus = throttle(
this.env,
this.messaging,
({ isTyping }) => this.async(() => this._notifyCurrentPartnerTypingStatus({ isTyping })),
2.5 * 1000
);
@@ -1038,7 +1038,7 @@ registerModel({
*/
registerOtherMemberTypingMember(partner) {
const timer = new Timer(
this.env,
this.messaging,
() => this.async(() => this._onOtherMemberLongTypingTimeout(partner)),
60 * 1000
);
@@ -14,7 +14,7 @@ registerModel({
this._loaderTimeout = undefined;
},
_willDelete() {
this.env.browser.clearTimeout(this._loaderTimeout);
this.messaging.browser.clearTimeout(this._loaderTimeout);
},
},
recordMethods: {
@@ -229,7 +229,7 @@ registerModel({
this.update({ isPreparingLoading: true });
this.async(() =>
new Promise(resolve => {
this._loaderTimeout = this.env.browser.setTimeout(resolve, 400);
this._loaderTimeout = this.messaging.browser.setTimeout(resolve, 400);
}
)).then(() => {
const isLoading = this.threadCache
@@ -240,7 +240,7 @@ registerModel({
}
return;
}
this.env.browser.clearTimeout(this._loaderTimeout);
this.messaging.browser.clearTimeout(this._loaderTimeout);
this.update({ isLoading: false, isPreparingLoading: false });
},
/**
@@ -15,11 +15,13 @@ QUnit.module('throttle_tests.js', {
this.throttles = [];
this.start = async params => {
const { env, widget } = await start(Object.assign({}, params, {
const res = await start(Object.assign({}, params, {
data: this.data,
}));
const { env, widget } = res;
this.env = env;
this.widget = widget;
return res;
};
},
afterEach() {
@@ -35,13 +37,13 @@ QUnit.module('throttle_tests.js', {
QUnit.test('single call', async function (assert) {
assert.expect(6);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
let hasInvokedFunc = false;
const throttledFunc = throttle(
this.env,
messaging,
() => {
hasInvokedFunc = true;
return 'func_result';
@@ -83,13 +85,13 @@ QUnit.test('single call', async function (assert) {
QUnit.test('2nd (throttled) call', async function (assert) {
assert.expect(8);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
let funcCalledAmount = 0;
const throttledFunc = throttle(
this.env,
messaging,
() => {
funcCalledAmount++;
return `func_result_${funcCalledAmount}`;
@@ -142,13 +144,13 @@ QUnit.test('2nd (throttled) call', async function (assert) {
QUnit.test('throttled call reinvocation', async function (assert) {
assert.expect(11);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
let funcCalledAmount = 0;
const throttledFunc = throttle(
this.env,
messaging,
() => {
funcCalledAmount++;
return `func_result_${funcCalledAmount}`;
@@ -220,12 +222,12 @@ QUnit.test('throttled call reinvocation', async function (assert) {
QUnit.test('flush throttled call', async function (assert) {
assert.expect(9);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
const throttledFunc = throttle(
this.env,
messaging,
() => {},
1000,
);
@@ -276,12 +278,12 @@ QUnit.test('flush throttled call', async function (assert) {
QUnit.test('cancel throttled call', async function (assert) {
assert.expect(10);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
const throttledFunc = throttle(
this.env,
messaging,
() => {},
1000,
{ silentCancelationErrors: false }
@@ -342,12 +344,12 @@ QUnit.test('cancel throttled call', async function (assert) {
QUnit.test('clear throttled call', async function (assert) {
assert.expect(9);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
const throttledFunc = throttle(
this.env,
messaging,
() => {},
1000,
{ silentCancelationErrors: false }
@@ -97,20 +97,20 @@ class _ThrottleFlushedError extends Error {
class Throttle {
/**
* @param {Object} env the OWL env
* @param {Messaging} messaging the messaging record.
* @param {function} func provided function for making throttled version.
* @param {integer} duration duration of the 'cool down' phase, i.e.
* the minimum duration between the most recent function call that has
* been made and the following function call (of course, assuming no flush
* in-between).
*/
constructor(env, func, duration) {
constructor(messaging, func, duration) {
/**
* Reference to the OWL envirionment. Useful to fine-tune control of
* Reference to the messaging record. Useful to fine-tune control of
* time flow in tests.
* @see mail/static/src/utils/test_utils.js:start.hasTimeControl
*/
this.env = env;
this.messaging = messaging;
/**
* Unique id of this throttle function. Useful for the ThrottleError
* management, in order to determine whether these errors come from
@@ -266,7 +266,7 @@ class Throttle {
const coolingDownDeferred = makeDeferred();
this._coolingDownDeferred = coolingDownDeferred;
this._isCoolingDown = true;
const cooldownTimeoutId = this.env.browser.setTimeout(
const cooldownTimeoutId = this.messaging.browser.setTimeout(
() => coolingDownDeferred.resolve(),
this._duration
);
@@ -283,7 +283,7 @@ class Throttle {
unexpectedError = error;
}
} finally {
this.env.browser.clearTimeout(cooldownTimeoutId);
this.messaging.browser.clearTimeout(cooldownTimeoutId);
this._coolingDownDeferred = undefined;
this._isCoolingDown = false;
}
@@ -312,7 +312,7 @@ class Throttle {
* - When a cooldown phase ends, any buffered function call will be performed
* and another cooldown phase will follow up.
*
* @param {Object} env the OWL env
* @param {Messaging} messaging the messaging record.
* @param {function} func the function to throttle.
* @param {integer} duration duration, in milliseconds, of the cooling down
* phase of the throttling.
@@ -330,12 +330,12 @@ class Throttle {
* of the provided function.
*/
function throttle(
env,
messaging,
func,
duration,
{ silentCancelationErrors = true } = {}
) {
const throttleObj = new Throttle(env, func, duration);
const throttleObj = new Throttle(messaging, func, duration);
const callable = async (...args) => {
try {
// await is important, otherwise errors are not intercepted.
@@ -14,11 +14,13 @@ QUnit.module('timer_tests.js', {
this.timers = [];
this.start = async (params) => {
const { env, widget } = await start(Object.assign({}, params, {
const res = await start(Object.assign({}, params, {
data: this.data,
}));
const { env, widget } = res;
this.env = env;
this.widget = widget;
return res;
};
},
afterEach() {
@@ -34,14 +36,14 @@ QUnit.module('timer_tests.js', {
QUnit.test('timer does not timeout on initialization', async function (assert) {
assert.expect(3);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
let hasTimedOut = false;
this.timers.push(
new Timer(
this.env,
messaging,
() => hasTimedOut = true,
0
)
@@ -68,14 +70,14 @@ QUnit.test('timer does not timeout on initialization', async function (assert) {
QUnit.test('timer start (duration: 0ms)', async function (assert) {
assert.expect(2);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
let hasTimedOut = false;
this.timers.push(
new Timer(
this.env,
messaging,
() => hasTimedOut = true,
0
)
@@ -97,14 +99,14 @@ QUnit.test('timer start (duration: 0ms)', async function (assert) {
QUnit.test('timer start observe termination (duration: 0ms)', async function (assert) {
assert.expect(6);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
let hasTimedOut = false;
this.timers.push(
new Timer(
this.env,
messaging,
() => {
hasTimedOut = true;
return 'timeout_result';
@@ -146,14 +148,14 @@ QUnit.test('timer start observe termination (duration: 0ms)', async function (as
QUnit.test('timer start (duration: 1000s)', async function (assert) {
assert.expect(5);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
let hasTimedOut = false;
this.timers.push(
new Timer(
this.env,
messaging,
() => hasTimedOut = true,
1000 * 1000
)
@@ -193,14 +195,14 @@ QUnit.test('timer start (duration: 1000s)', async function (assert) {
QUnit.test('[no cancelation intercept] timer start then immediate clear (duration: 0ms)', async function (assert) {
assert.expect(4);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
let hasTimedOut = false;
this.timers.push(
new Timer(
this.env,
messaging,
() => hasTimedOut = true,
0
)
@@ -234,14 +236,14 @@ QUnit.test('[no cancelation intercept] timer start then immediate clear (duratio
QUnit.test('[no cancelation intercept] timer start then clear before timeout (duration: 1000ms)', async function (assert) {
assert.expect(4);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
let hasTimedOut = false;
this.timers.push(
new Timer(
this.env,
messaging,
() => hasTimedOut = true,
1000
)
@@ -276,14 +278,14 @@ QUnit.test('[no cancelation intercept] timer start then clear before timeout (du
QUnit.test('[no cancelation intercept] timer start then reset before timeout (duration: 1000ms)', async function (assert) {
assert.expect(5);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
let hasTimedOut = false;
this.timers.push(
new Timer(
this.env,
messaging,
() => hasTimedOut = true,
1000
)
@@ -324,14 +326,14 @@ QUnit.test('[no cancelation intercept] timer start then reset before timeout (du
QUnit.test('[with cancelation intercept] timer start then immediate clear (duration: 0ms)', async function (assert) {
assert.expect(5);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
let hasTimedOut = false;
this.timers.push(
new Timer(
this.env,
messaging,
() => hasTimedOut = true,
0,
{ silentCancelationErrors: false }
@@ -367,14 +369,14 @@ QUnit.test('[with cancelation intercept] timer start then immediate clear (durat
QUnit.test('[with cancelation intercept] timer start then immediate reset (duration: 0ms)', async function (assert) {
assert.expect(9);
await this.start({
const { messaging } = await this.start({
hasTimeControl: true,
});
let hasTimedOut = false;
this.timers.push(
new Timer(
this.env,
messaging,
() => hasTimedOut = true,
0,
{ silentCancelationErrors: false }
+6 -6
View File
@@ -38,7 +38,7 @@ import { makeDeferred } from '@mail/utils/deferred/deferred';
class Timer {
/**
* @param {Object} env the OWL env
* @param {Messaging} messaging the messaging record.
* @param {function} onTimeout
* @param {integer} duration
* @param {Object} [param3={}]
@@ -48,8 +48,8 @@ class Timer {
* @see TimerClearedError for when timer has been aborted from `.clear()`
* or `.reset()`.
*/
constructor(env, onTimeout, duration, { silentCancelationErrors = true } = {}) {
this.env = env;
constructor(messaging, onTimeout, duration, { silentCancelationErrors = true } = {}) {
this.messaging = messaging;
/**
* Determine whether the timer has a pending timeout.
*/
@@ -90,7 +90,7 @@ class Timer {
* when this timer is running.
*/
clear() {
this.env.browser.clearTimeout(this._timeoutId);
this.messaging.browser.clearTimeout(this._timeoutId);
this.isRunning = false;
if (!this._timeoutDeferred) {
return;
@@ -121,7 +121,7 @@ class Timer {
this.isRunning = true;
const timeoutDeferred = makeDeferred();
this._timeoutDeferred = timeoutDeferred;
const timeoutId = this.env.browser.setTimeout(
const timeoutId = this.messaging.browser.setTimeout(
() => {
this.isRunning = false;
timeoutDeferred.resolve(this._onTimeout());
@@ -143,7 +143,7 @@ class Timer {
throw error;
}
} finally {
this.env.browser.clearTimeout(timeoutId);
this.messaging.browser.clearTimeout(timeoutId);
this._timeoutDeferred = undefined;
this.isRunning = false;
}