diff --git a/client/modules/crm/src/views/calendar/calendar-page.js b/client/modules/crm/src/views/calendar/calendar-page.js index cd697a6000..f5bc89f7f8 100644 --- a/client/modules/crm/src/views/calendar/calendar-page.js +++ b/client/modules/crm/src/views/calendar/calendar-page.js @@ -67,9 +67,9 @@ class CalendarPage extends View { /** * @private - * @type {DebounceHelper} + * @type {DebounceHelper|null} */ - webSocketDebounceHelper + webSocketDebounceHelper = null /** * @private @@ -77,6 +77,12 @@ class CalendarPage extends View { */ webSocketDebounceInterval = 500 + /** + * @private + * @type {number} + */ + webSocketBlockInterval = 1000 + /** * A shortcut-key => action map. * @@ -228,6 +234,7 @@ class CalendarPage extends View { this.webSocketDebounceHelper = new DebounceHelper({ interval: this.webSocketDebounceInterval, + blockInterval: this.webSocketBlockInterval, handler: () => this.handleWebSocketUpdate(), }); @@ -254,6 +261,17 @@ class CalendarPage extends View { this.getCalendarView()?.actionRefresh({suppressLoadingAlert: true}); } + /** + * @private + */ + onSave() { + if (!this.webSocketDebounceHelper) { + return; + } + + this.webSocketDebounceHelper.block() + } + afterRender() { this.$el.focus(); } @@ -284,6 +302,9 @@ class CalendarPage extends View { this.getRouter().navigate(url, {trigger: trigger}); } + /** + * @private + */ setupCalendar() { const viewName = this.getMetadata().get(['clientDefs', 'Calendar', 'calendarView']) || 'crm:views/calendar/calendar'; @@ -294,6 +315,7 @@ class CalendarPage extends View { userName: this.options.userName, mode: this.mode, fullSelector: '#main > .calendar-container', + onSave: () => this.onSave(), }, view => { let initial = true; @@ -330,6 +352,9 @@ class CalendarPage extends View { }); } + /** + * @private + */ setupTimeline() { const viewName = this.getMetadata().get(['clientDefs', 'Calendar', 'timelineView']) || 'crm:views/calendar/timeline'; @@ -339,6 +364,7 @@ class CalendarPage extends View { userId: this.options.userId, userName: this.options.userName, fullSelector: '#main > .calendar-container', + onSave: () => this.onSave(), }, view => { let initial = true; diff --git a/client/src/helpers/util/debounce.js b/client/src/helpers/util/debounce.js index 7a002c858f..3ee285e684 100644 --- a/client/src/helpers/util/debounce.js +++ b/client/src/helpers/util/debounce.js @@ -37,20 +37,49 @@ export default class DebounceHelper { * @type {boolean} * @private */ - _blocked = false + blocked = false /** - * * @type {boolean} * @private */ - _calledWhenBlocked = false + blockedInProcess = false + /** + * @type {boolean} + * @private + */ + calledWhenProcessBlocked = false + + /** + * @type {number} + * @private + */ + interval = 500 + + /** + * @type {number} + * @private + */ + blockInterval = 1000 + + /** + * @type {number} + * @private + */ + blockedCallCount = 0 + + /** + * @type {number|null} + * @private + */ + blockTimeoutId = null /** * @param {{ * handler: function(...*), - * interval: number, + * interval?: number, + * blockInterval?: number, * }} options * @param options */ @@ -61,11 +90,8 @@ export default class DebounceHelper { */ this.handler = options.handler; - /** - * @private - * @type {number} - */ - this.interval = options.interval; + this.interval = options.interval ?? this.interval; + this.blockInterval = options.blockInterval ?? this.blockInterval; } /** @@ -75,21 +101,27 @@ export default class DebounceHelper { */ process() { const handle = () => { - if (this._blocked) { - this._calledWhenBlocked = true; + if (this.blocked) { + this.blockedCallCount ++; + + return; + } + + if (this.blockedInProcess) { + this.calledWhenProcessBlocked = true; return; } this.handler(arguments); - this._blocked = true; + this.blockedInProcess = true; setTimeout(() => { - const reRun = this._calledWhenBlocked; + const reRun = this.calledWhenProcessBlocked; - this._blocked = false; - this._calledWhenBlocked = false; + this.blockedInProcess = false; + this.calledWhenProcessBlocked = false; if (reRun) { handle(); @@ -99,4 +131,27 @@ export default class DebounceHelper { handle(); } + + /** + * Block for a while. + * + * @since 9.2.0 + */ + block() { + this.blocked = true; + + if (this.blockTimeoutId) { + clearTimeout(this.blockTimeoutId); + } + + this.blockTimeoutId = setTimeout(() => { + this.blocked = false; + const toProcess = this.blockedCallCount > 1; + this.blockedCallCount = 0; + + if (toProcess) { + this.process(); + } + }, this.blockInterval) + } }