Skip to content
Permalink
Browse files

[WIP] mail: chat window manager

  • Loading branch information...
alexkuhn committed May 13, 2019
1 parent 25dc4d7 commit 1a9acd8cfe80305de4f207b149d48bc6f56ceff0
Showing with 1,100 additions and 813 deletions.
  1. +5 −0 addons/mail/__manifest__.py
  2. +0 −1 addons/mail/static/src/js/wip/old_widget/discuss.js
  3. +28 −22 addons/mail/static/src/js/wip/service/chat_window_service.js
  4. +15 −4 addons/mail/static/src/js/wip/service/store_service.js
  5. +15 −7 addons/mail/static/src/js/wip/store/actions.js
  6. +21 −0 addons/mail/static/src/js/wip/store/mutations.js
  7. +130 −0 addons/mail/static/src/js/wip/widget/autoresize_input.js
  8. +148 −0 addons/mail/static/src/js/wip/widget/chat_window.js
  9. +85 −0 addons/mail/static/src/js/wip/widget/chat_window_hidden_menu.js
  10. +185 −635 addons/mail/static/src/js/wip/widget/chat_window_manager.js
  11. +47 −8 addons/mail/static/src/js/wip/widget/composer.js
  12. +17 −0 addons/mail/static/src/js/wip/widget/discuss_root.js
  13. +1 −1 addons/mail/static/src/js/wip/widget/discuss_sidebar_item.js
  14. +2 −2 addons/mail/static/src/js/wip/widget/thread.js
  15. 0 addons/mail/static/src/scss/wip/{ → old_widget}/discuss.scss
  16. +93 −0 addons/mail/static/src/scss/wip/widget/chat_window.scss
  17. +22 −0 addons/mail/static/src/scss/wip/widget/chat_window_hidden_menu.scss
  18. +18 −0 addons/mail/static/src/scss/wip/widget/chat_window_manager.scss
  19. +69 −0 addons/mail/static/src/scss/wip/widget/common.scss
  20. +19 −5 addons/mail/static/src/scss/wip/{ → widget}/composer.scss
  21. 0 addons/mail/static/src/scss/wip/{ → widget}/discuss_mobile_mailbox_selection.scss
  22. 0 addons/mail/static/src/scss/wip/{ → widget}/discuss_mobile_navbar.scss
  23. 0 addons/mail/static/src/scss/wip/{ → widget}/discuss_root.scss
  24. 0 addons/mail/static/src/scss/wip/{ → widget}/discuss_sidebar.scss
  25. +0 −61 addons/mail/static/src/scss/wip/{ → widget}/discuss_sidebar_item.scss
  26. 0 addons/mail/static/src/scss/wip/{ → widget}/emojis_popover.scss
  27. +1 −0 addons/mail/static/src/scss/wip/{ → widget}/message.scss
  28. +3 −2 addons/mail/static/src/scss/wip/{ → widget}/message_list.scss
  29. 0 addons/mail/static/src/scss/wip/{ → widget}/thread.scss
  30. +10 −0 addons/mail/static/src/xml/wip/widget/autoresize_input.xml
  31. +32 −0 addons/mail/static/src/xml/wip/widget/chat_window.xml
  32. +10 −0 addons/mail/static/src/xml/wip/widget/chat_window_hidden_menu.xml
  33. +19 −0 addons/mail/static/src/xml/wip/widget/chat_window_manager.xml
  34. +44 −0 addons/mail/static/src/xml/wip/widget/common.xml
  35. +33 −23 addons/mail/static/src/xml/wip/widget/composer.xml
  36. +3 −2 addons/mail/static/src/xml/wip/widget/discuss_root.xml
  37. +1 −25 addons/mail/static/src/xml/wip/widget/discuss_sidebar_item.xml
  38. +4 −2 addons/mail/static/src/xml/wip/widget/message.xml
  39. +1 −1 addons/mail/static/src/xml/wip/widget/message_list.xml
  40. +18 −11 addons/mail/views/mail_templates.xml
  41. +1 −1 addons/web/static/src/js/chrome/abstract_web_client.js
@@ -64,6 +64,11 @@
'static/src/xml/wip/old_widget/discuss.xml',
'static/src/xml/wip/old_widget/discuss_invite_partner_dialog.xml',
'static/src/xml/wip/widget/autocomplete_input.xml',
'static/src/xml/wip/widget/autoresize_input.xml',
'static/src/xml/wip/widget/chat_window.xml',
'static/src/xml/wip/widget/chat_window_hidden_menu.xml',
'static/src/xml/wip/widget/chat_window_manager.xml',
'static/src/xml/wip/widget/common.xml',
'static/src/xml/wip/widget/composer.xml',
'static/src/xml/wip/widget/discuss_mobile_mailbox_selection.xml',
'static/src/xml/wip/widget/discuss_mobile_navbar.xml',
@@ -6,7 +6,6 @@ const StoreMixin = require('mail.wip.old_widget.StoreMixin');
const Root = require('mail.wip.widget.DiscussRoot');

const AbstractAction = require('web.AbstractAction');
const config = require('web.config');
const core = require('web.core');
const session = require('web.session');

@@ -1,41 +1,47 @@
odoo.define('mail.wip.service.ChatWindowService', function (require) {
"use strict";

var StoreMixin = require('mail.wip.old_widget.StoreMixin');
var Root = require('mail.wip.widget.ChatWindowManager');
const StoreMixin = require('mail.wip.old_widget.StoreMixin');
const Root = require('mail.wip.widget.ChatWindowManager');

var AbstractService = require('web.AbstractService');
var core = require('web.core');
const AbstractService = require('web.AbstractService');
const core = require('web.core');
const session = require('web.session');

var _t = core._t;
const _t = core._t;

var ChatWindowService = AbstractService.extend(StoreMixin, {
const ChatWindowService = AbstractService.extend(StoreMixin, {
DEBUG: true,
dependencies: ['store'],
/**
* @override {web.AbstractService}
*/
init: function () {
init() {
this._super.apply(this, arguments);
if (this.DEBUG) {
window.chat_window_manager = this;
}
},
/**
* @override {web.AbstractService}
*/
async start() {
start() {
this._super.apply(this, arguments);
await this.awaitStore();
const env = {
store: this.store,
call: (...args) => this.call(...args),
do_action: (...args) => this.do_action(...args),
rpc: (...args) => this._rpc(...args),
_t,
};
this._root = new Root(env);
this._root.mount(this.$el[0]); // aku todo
core.bus.on('web_client_ready', this, async () => {
await this.awaitStore();
const env = {
_t,
qweb: core.qwebOwl,
session,
store: this.store,
call: (...args) => this.call(...args),
do_action: (...args) => this.do_action(...args),
rpc: (...args) => this._rpc(...args),
};
this.root = new Root(env);
this.root.mount(document.querySelector('body'));
});
},
});

// core.serviceRegistry.add('chat_window', ChatWindowService);
core.serviceRegistry.add('chat_window', ChatWindowService);

return ChatWindowService;

@@ -22,6 +22,9 @@ function initializeState() {
$pinnedThreads: [],
FETCH_LIMIT: 30, // max number of fetched messages from the server
cannedResponses: {},
chat_window_manager: {
$detachedThreads: [],
},
commands: {},
discuss: {
$thread: undefined,
@@ -30,6 +33,9 @@ function initializeState() {
menu_id: undefined,
stringifiedDomain: '[]',
},
global: {
innerWidth: window.innerWidth,
},
isMobile: config.device.isMobile,
isMyselfModerator: false,
mailFailures: {},
@@ -39,7 +45,7 @@ function initializeState() {
partners: { odoobot }, // all partner infos
pinnedDmPartnerIDs: [], // partner_ids we have a pinned DM chat with
threadCaches: {},
threads: {} // all threads, including channels, DM, mailboxes, document threads, ...
threads: {}, // all threads, including channels, DM, mailboxes, document threads, ...
};
}

@@ -72,10 +78,15 @@ const StoreService = AbstractService.extend({
*/
start() {
this.ready = new Promise(resolve =>
this.store.dispatch('init', { ready: resolve })
this.store.dispatch('init', {
ready: () => {
this.store.commit('global/resize');
resolve();
}
})
);
window.addEventListener('resize', _.throttle(() => {
this.store.commit('update', { isMobile: config.device.isMobile });
window.addEventListener('resize', _.debounce(() => {
this.store.commit('global/resize');
}), 100);
},

@@ -93,8 +93,12 @@ const actions = {
}
});
const $thread = commit('thread/create', { ...data });
if (autoselect && state.discuss.open) {
commit('discuss/update', { $thread });
if (autoselect) {
if (state.discuss.open) {
commit('discuss/update', { $thread });
} else {
commit('chat_window_manager/open', { $thread });
}
}
},
/**
@@ -120,11 +124,15 @@ const actions = {
args: [[channelID]]
});
const $thread = commit('thread/create', { ...data });
if (autoselect && state.discuss.open) {
commit('discuss/update', {
$thread,
domain: [],
});
if (autoselect) {
if (state.discuss.open) {
commit('discuss/update', {
$thread,
domain: [],
});
} else {
commit('chat_window_manager/open', { $thread });
}
}
},
/**
@@ -7,12 +7,25 @@ const Partner = require('mail.wip.model.Partner');
const Thread = require('mail.wip.model.Thread');
const ThreadCache = require('mail.wip.model.ThreadCache');

const config = require('web.config');
const core = require('web.core');
const session = require('web.session');

const _t = core._t;

const mutations = {
/**
* @param {Object} param0
* @param {Object} param0.state
* @param {Object} param1
* @param {string} param1.$thread
*/
'chat_window_manager/open'({ state }, { $thread }) {
if (state.chat_window_manager.$detachedThreads.includes($thread)) {
return;
}
state.chat_window_manager.$detachedThreads.push($thread);
},
/**
* @param {Object} param0
* @param {Object} param0.state
@@ -925,6 +938,14 @@ const mutations = {
'update'({ state }, changes) {
Object.assign(state, changes);
},
/**
* @param {Object} param0
* @param {Object} param0.state
*/
'global/resize'({ state }) {
state.global.innerWidth = window.innerWidth;
state.isMobile = config.device.isMobile;
},
};

return mutations;
@@ -0,0 +1,130 @@
odoo.define('mail.wip.widget.AutoresizeInput', function () {
'use strict';

const { Component } = owl;

class AutoresizeInput extends Component {

/**
* @param {...any} args
*/
constructor(...args) {
super(...args);
this.template = 'mail.wip.widget.AutoresizeInput';
this._scrollable = false;
}

mounted() {
this.el.setAttribute('rows', this.options.rows);
this._compute();
}

//--------------------------------------------------------------------------
// Getter / Setter
//--------------------------------------------------------------------------

/**
* @return {Object}
*/
get options() {
let options = this.props.options || {};
if (!('rows' in options)) {
options.rows = 1;
}
if (!('maxHeight' in options)) {
options.maxHeight = 200;
}
return options;
}

/**
* @return {string}
*/
get value() {
return this.el.value;
}

/**
* @param {string} newValue
*/
set value(newValue) {
this.el.value = newValue;
}

//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------

focus() {
this.el.focus();
}

/**
* @return {Object}
*/
getSelectionRange() {
return {
start: this.el.selectionStart,
end: this.el.selectionEnd,
};
}

/**
* @param {integer} start
* @param {integer} end
*/
setSelectionRange(start, end) {
this.el.setSelectionRange(start, end);
}

//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------

/**
* @private
*/
_compute() {
let prevScrollTop;
if (this._scrollable) {
prevScrollTop = this.el.scrollTop;
}
this.el.style['overflow-y'] = 'hidden';
this.el.style['height'] = 'auto';
this.el.style['height'] = `${this.el.scrollHeight}px`;
this.el.style['resize'] = 'none';
if (this.el.scrollHeight > this.options.maxHeight) {
this.el.style['height'] = `${this.options.maxHeight}px`;
this.el.style['overflow-y'] = 'auto';
if (prevScrollTop && this.el.scrollTop !== prevScrollTop) {
this.el.scrollTop = prevScrollTop;
}
this._scrollable = true;
} else {
this.el.style['overflow-y'] = 'hidden';
this._scrollable = false;
}
}

//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------

/**
* @private
*/
_onInput() {
this. _compute();
}
/**
* @private
* @param {KeyboardEvent} ev
*/
_onKeydown(ev) {
this.trigger('keydown', ev);
}
}

return AutoresizeInput;

});
Oops, something went wrong.

0 comments on commit 1a9acd8

Please sign in to comment.
You can’t perform that action at this time.