1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
odoo.define('bus.WebClient', function (require) {
"use strict";
const core = require('web.core');
const WebClient = require('web.WebClient');
const _t = core._t;
WebClient.include({
//----------------------------------------------------------------------
// Public
//----------------------------------------------------------------------
/**
* Detects the presence of assets in DOM's HEAD
*
* @override
*/
async start() {
this._assetsChangedNotificationId = null;
this._assets = {};
await this._super(...arguments);
},
/**
* Assigns handler to bus notification
*
* @override
*/
show_application() {
const shown = this._super(...arguments);
document.querySelectorAll('*[data-asset-xmlid]').forEach(el => {
this._assets[el.getAttribute('data-asset-xmlid')] = el.getAttribute('data-asset-version');
});
this.call('bus_service', 'onNotification', this, this._onNotification);
this.call('bus_service', 'addChannel', 'bundle_changed');
return shown;
},
//----------------------------------------------------------------------
// Private
//----------------------------------------------------------------------
/**
* Displays one notification on user's screen when assets have changed
*
* @private
*/
_displayBundleChangedNotification() {
if (!this._assetsChangedNotificationId) {
// Wrap the notification inside a delay.
// The server may be overwhelmed with recomputing assets
// We wait until things settle down
clearTimeout(this._bundleNotifTimerID);
this._bundleNotifTimerID = setTimeout(() => {
this._assetsChangedNotificationId = this.call('notification', 'notify', {
title: _t('Refresh'),
message: _t('The page appears to be out of date.'),
sticky: true,
onClose: () => {
this._assetsChangedNotificationId = null;
},
buttons: [{
text: _t('Refresh'),
primary: true,
click: () => {
window.location.reload(true);
}
}],
});
}, this._getBundleNotificationDelay());
}
},
/**
* Computes a random delay to avoid hammering the server
* when bundles change with all the users reloading
* at the same time
*
* @private
* @return {number} delay in milliseconds
*/
_getBundleNotificationDelay() {
return 10000 + Math.floor(Math.random()*50) * 1000;
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* Reacts to bus's notification
*
* @private
* @param {Array} notifications: list of received notifications
*/
_onNotification(notifications) {
for (const notif of notifications) {
if (notif[0][1] === 'bundle_changed') {
const bundleXmlId = notif[1][0];
const bundleVersion = notif[1][1];
if (bundleXmlId in this._assets && bundleVersion !== this._assets[bundleXmlId]) {
this._displayBundleChangedNotification();
break;
}
}
}
}
});
});
|