summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/js/thread.js
diff options
context:
space:
mode:
authorAlexandre Kühn <aku@odoo.com>2018-07-04 13:48:20 +0200
committerAlexandre Kühn <aku@odoo.com>2018-07-19 13:58:34 +0200
commit448cceffaa812fa5e10f67b290f4bfc93369800f (patch)
treee8fde463ca9849160874f70ced0bc18c7b0caeab /addons/mail/static/src/js/thread.js
parentcb7add2ebd50c1981e35bb12a3e52a69a58bc05f (diff)
[RENAME] im_livechat,mail: rename widget 'thread.js' file to 'thread_widget.js'
It is a bit annoying to have two files named 'thread.js', one being the widget and the other the mail model.
Diffstat (limited to 'addons/mail/static/src/js/thread.js')
-rw-r--r--addons/mail/static/src/js/thread.js538
1 files changed, 0 insertions, 538 deletions
diff --git a/addons/mail/static/src/js/thread.js b/addons/mail/static/src/js/thread.js
deleted file mode 100644
index 7d4833e81cd..00000000000
--- a/addons/mail/static/src/js/thread.js
+++ /dev/null
@@ -1,538 +0,0 @@
-odoo.define('mail.widget.Thread', function (require) {
-"use strict";
-
-var DocumentViewer = require('mail.DocumentViewer');
-var mailUtils = require('mail.utils');
-
-var core = require('web.core');
-var time = require('web.time');
-var Widget = require('web.Widget');
-
-var QWeb = core.qweb;
-var _t = core._t;
-
-var ORDER = {
- ASC: 1,
- DESC: -1,
-};
-
-var READ_MORE = _t("read more");
-var READ_LESS = _t("read less");
-
-/**
- * This is a generic widget to render a chat thread
- */
-var ThreadWidget = Widget.extend({
- className: 'o_mail_thread',
-
- events: {
- 'click a': '_onClickRedirect',
- 'click img': '_onClickRedirect',
- 'click strong': '_onClickRedirect',
- 'click .o_thread_show_more': '_onClickShowMore',
- 'click .o_attachment_download': '_onAttachmentDownload',
- 'click .o_attachment_view': '_onAttachmentView',
- 'click .o_thread_message_needaction': '_onClickMessageNeedaction',
- 'click .o_thread_message_star': '_onClickMessageStar',
- 'click .o_thread_message_reply': '_onClickMessageReply',
- 'click .oe_mail_expand': '_onClickMailExpand',
- 'click .o_thread_message': '_onClickMessage',
- 'click': '_onClick',
- 'click .o_thread_message_email_exception': '_onClickEmailException',
- 'click .o_thread_message_moderation': '_onClickMessageModeration',
- 'change .moderation_checkbox': '_onChangeModerationCheckbox',
- },
-
- /**
- * @override
- * @param {widget} parent
- * @param {Object} options
- */
- init: function (parent, options) {
- this._super.apply(this, arguments);
- // options when the thread is enabled (e.g. can send message,
- // interact on messages, etc.)
- this._enabledOptions = _.defaults(options || {}, {
- displayOrder: ORDER.ASC,
- displayMarkAsRead: true,
- displayStars: true,
- displayDocumentLinks: true,
- displayAvatars: true,
- squashCloseMessages: true,
- displayEmailIcons: true,
- displayReplyIcons: false,
- loadMoreOnScroll: false,
- });
- // options when the thread is disabled
- this._disabledOptions = {
- displayOrder: this._enabledOptions.displayOrder,
- displayMarkAsRead: false,
- displayStars: false,
- displayDocumentLinks: false,
- displayAvatars: this._enabledOptions.displayAvatars,
- squashCloseMessages: false,
- displayEmailIcons: false,
- displayReplyIcons: false,
- loadMoreOnScroll: this._enabledOptions.loadMoreOnScroll,
- };
- this._selectedMessageID = null;
- },
-
- /**
- * @override
- */
- destroy: function () {
- clearInterval(this._updateTimestampsInterval);
- },
-
- /**
- * @param {mail.model.AbstractMessage[]} messages list of messages of the
- * thread, ordered by increasing IDs (a higher ID means a more recent
- * message).
- * @param {Object} [options]
- * @param {integer} [options.displayOrder=ORDER.ASC] order of displaying
- * messages in the thread:
- * - ORDER.ASC: last message is at the bottom of the thread
- * - ORDER.DESC: last message is at the top of the thread
- * @param {boolean} [options.displayLoadMore]
- * @param {boolean} [options.isCreateMode]
- * @param {boolean} [options.squashCloseMessages]
- */
- render: function (messages, options) {
- var self = this;
-
- // copy so that reverse do not alter order in the thread object
- messages = _.clone(messages);
-
- var modeOptions = options.isCreateMode ? this._disabledOptions :
- this._enabledOptions;
-
- // attachments ordered by messages order (increasing ID)
- this.attachments = _.uniq(_.flatten(_.map(messages, function (message) {
- return message.getAttachments();
- })));
-
- if (modeOptions.displayOrder === ORDER.DESC) {
- messages.reverse();
- }
- options = _.extend({}, modeOptions, options, {
- selectedMessageID: this._selectedMessageID,
- });
-
- // Hide avatar and info of a message if that message and the previous
- // one are both comments wrote by the same author at the same minute
- // and in the same document (users can now post message in documents
- // directly from a channel that follows it)
- var prevMessage;
- _.each(messages, function (message) {
- if (
- // is first message of thread
- !prevMessage ||
- // more than 1 min. elasped
- (Math.abs(message.getDate().diff(prevMessage.getDate())) > 60000) ||
- prevMessage.getType() !== 'comment' ||
- message.getType() !== 'comment' ||
- // from a different author
- (prevMessage.getAuthorID() !== message.getAuthorID()) ||
- (
- // messages are linked to a document thread
- (
- prevMessage.isLinkedToDocumentThread() &&
- message.isLinkedToDocumentThread()
- ) &&
- (
- // are from different documents
- prevMessage.getDocumentModel() !== message.getDocumentModel() ||
- prevMessage.getDocumentID() !== message.getDocumentID()
- )
- )
- ) {
- message.displayAuthor(true);
- } else {
- message.displayAuthor(!options.squashCloseMessages);
- }
- prevMessage = message;
- });
- this.$el.html(QWeb.render('mail.widget.Thread', {
- messages: messages,
- options: options,
- ORDER: ORDER,
- dateFormat: time.getLangDatetimeFormat(),
- }));
-
- _.each(messages, function (message) {
- var $message = self.$('.o_thread_message[data-message-id="'+ message.getID() +'"]');
- $message.find('.o_mail_timestamp').data('date', message.getDate());
-
- self._insertReadMore($message);
- });
-
- if (!this._updateTimestampsInterval) {
- this.updateTimestampsInterval = setInterval(function () {
- self._updateTimestamps();
- }, 1000*60);
- }
- },
-
- //--------------------------------------------------------------------------
- // Public
- //--------------------------------------------------------------------------
-
- getScrolltop: function () {
- return this.$el.scrollTop();
- },
- /**
- * State whether the bottom of the thread is visible or not,
- * with a tolerance of 5 pixels
- *
- * @return {boolean}
- */
- isAtBottom: function () {
- var fullHeight = this.el.scrollHeight;
- var topHiddenHeight = this.$el.scrollTop();
- var visibleHeight = this.$el.outerHeight();
- var bottomHiddenHeight = fullHeight - topHiddenHeight - visibleHeight;
- return bottomHiddenHeight < 5;
- },
- /**
- * Removes a message and re-renders the thread
- *
- * @param {integer} [messageID] the id of the removed message
- * @param {mail.model.AbstractMessage[]} [messages] the list of messages to
- * display, without the removed one
- * @param {Object} [options] options for the thread rendering
- */
- removeMessageAndRender: function (messageID, messages, options) {
- var self = this;
- var done = $.Deferred();
- this.$('.o_thread_message[data-message-id="' + messageID + '"]')
- .fadeOut({
- done: function () {
- self.render(messages, options);
- done.resolve();
- },
- duration: 200,
- });
- return done;
- },
- /**
- * Scroll to the bottom of the thread
- */
- scrollToBottom: function () {
- this.$el.scrollTop(this.el.scrollHeight);
- },
- /**
- * Scrolls the thread to a given message
- *
- * @param {integer} options.messageID the ID of the message to scroll to
- * @param {integer} [options.duration]
- * @param {boolean} [options.onlyIfNecessary]
- */
- scrollToMessage: function (options) {
- var $target = this.$('.o_thread_message[data-message-id="' + options.messageID + '"]');
- if (options.onlyIfNecessary) {
- var delta = $target.parent().height() - $target.height();
- var offset = delta < 0 ?
- 0 :
- delta - ($target.offset().top - $target.offsetParent().offset().top);
- offset = - Math.min(offset, 0);
- this.$el.scrollTo("+=" + offset + "px", options.duration);
- } else if ($target.length) {
- this.$el.scrollTo($target);
- }
- },
- /**
- * Scroll to the specific position in pixel
- *
- * If no position is provided, scroll to the bottom of the thread
- *
- * @param {integer} [position] distance from top to position in pixels.
- * If not provided, scroll to the bottom.
- */
- scrollToPosition: function (position) {
- if (position) {
- this.$el.scrollTop(position);
- } else {
- this.scrollToBottom();
- }
- },
- /**
- * Toggle all the moderation checkboxes in the thread
- *
- * @param {boolean} checked if true, check the boxes,
- * otherwise uncheck them.
- */
- toggleModerationCheckboxes: function (checked) {
- this.$('.moderation_checkbox').prop('checked', checked);
- },
- /**
- * Unselect the selected message
- */
- unselectMessage: function () {
- this.$('.o_thread_message').removeClass('o_thread_selected_message');
- this._selectedMessageID = null;
- },
-
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- /**
- * Modifies $element to add the 'read more/read less' functionality
- * All element nodes with 'data-o-mail-quote' attribute are concerned.
- * All text nodes after a ``#stopSpelling`` element are concerned.
- * Those text nodes need to be wrapped in a span (toggle functionality).
- * All consecutive elements are joined in one 'read more/read less'.
- *
- * @private
- * @param {jQuery} $element
- */
- _insertReadMore: function ($element) {
- var self = this;
-
- var groups = [];
- var readMoreNodes;
-
- // nodeType 1: element_node
- // nodeType 3: text_node
- var $children = $element.contents()
- .filter(function () {
- return this.nodeType === 1 ||
- this.nodeType === 3 &&
- this.nodeValue.trim();
- });
-
- _.each($children, function (child) {
- var $child = $(child);
-
- // Hide Text nodes if "stopSpelling"
- if (
- child.nodeType === 3 &&
- $child.prevAll('[id*="stopSpelling"]').length > 0
- ) {
- // Convert Text nodes to Element nodes
- $child = $('<span>', {
- text: child.textContent,
- 'data-o-mail-quote': '1',
- });
- child.parentNode.replaceChild($child[0], child);
- }
-
- // Create array for each 'read more' with nodes to toggle
- if (
- $child.attr('data-o-mail-quote') ||
- (
- $child.get(0).nodeName === 'BR' &&
- $child.prev('[data-o-mail-quote="1"]').length > 0
- )
- ) {
- if (!readMoreNodes) {
- readMoreNodes = [];
- groups.push(readMoreNodes);
- }
- $child.hide();
- readMoreNodes.push($child);
- } else {
- readMoreNodes = undefined;
- self._insertReadMore($child);
- }
- });
-
- _.each(groups, function (group) {
- // Insert link just before the first node
- var $readMore = $('<a>', {
- class: 'o_mail_read_more',
- href: '#',
- text: READ_MORE,
- }).insertBefore(group[0]);
-
- // Toggle All next nodes
- var isReadMore = true;
- $readMore.click(function (e) {
- e.preventDefault();
- isReadMore = !isReadMore;
- _.each(group, function ($child) {
- $child.hide();
- $child.toggle(!isReadMore);
- });
- $readMore.text(isReadMore ? READ_MORE : READ_LESS);
- });
- });
- },
-
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- /**
- * @private
- * @param {Object} options
- * @param {integer} [options.channelID]
- * @param {string} options.model
- * @param {integer} options.id
- */
- _redirect: _.debounce(function (options) {
- if ('channelID' in options) {
- this.trigger('redirect_to_channel', options.channelID);
- } else {
- this.trigger('redirect', options.model, options.id);
- }
- }, 500, true),
- /**
- * @private
- */
- _updateTimestamps: function () {
- var isAtBottom = this.isAtBottom();
- this.$('.o_mail_timestamp').each(function () {
- var date = $(this).data('date');
- $(this).html(mailUtils.timeFromNow(date));
- });
- if (isAtBottom && !this.isAtBottom()) {
- this.scrollToBottom();
- }
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * @private
- * @param {MouseEvent} event
- */
- _onAttachmentDownload: function (event) {
- event.stopPropagation();
- },
- /**
- * @private
- * @param {MouseEvent} event
- */
- _onAttachmentView: function (event) {
- event.stopPropagation();
- var activeAttachmentID = $(event.currentTarget).data('id');
- if (activeAttachmentID) {
- var attachmentViewer = new DocumentViewer(this, this.attachments, activeAttachmentID);
- attachmentViewer.appendTo($('body'));
- }
- },
- /**
- * @private
- * @param {MouseEvent} ev
- */
- _onChangeModerationCheckbox: function (ev) {
- this.trigger_up('update_moderation_buttons');
- },
- /**
- * @private
- */
- _onClick: function () {
- if (this._selectedMessageID) {
- this.unselectMessage();
- this.trigger('unselect_message');
- }
- },
- /**
- * @private
- * @param {MouseEvent} ev
- */
- _onClickEmailException: function (ev) {
- var messageID = $(ev.currentTarget).data('message-id');
- this.do_action('mail.mail_resend_message_action', {
- additional_context: {
- mail_message_to_resend: messageID
- }
- });
- },
- /**
- * @private
- * @param {MouseEvent} ev
- */
- _onClickMailExpand: function (ev) {
- ev.preventDefault();
- },
- /**
- * @private
- * @param {MouseEvent} ev
- */
- _onClickMessage: function (ev) {
- $(ev.currentTarget).toggleClass('o_thread_selected_message');
- },
- /**
- * @private
- * @param {MouseEvent} ev
- */
- _onClickMessageNeedaction: function (ev) {
- var messageID = $(ev.currentTarget).data('message-id');
- this.trigger('mark_as_read', messageID);
- },
- /**
- * @private
- * @param {MouseEvent} ev
- */
- _onClickMessageReply: function (ev) {
- this._selectedMessageID = $(ev.currentTarget).data('message-id');
- this.$('.o_thread_message').removeClass('o_thread_selected_message');
- this.$('.o_thread_message[data-message-id="' + this._selectedMessageID + '"]')
- .addClass('o_thread_selected_message');
- this.trigger('select_message', this._selectedMessageID);
- ev.stopPropagation();
- },
- /**
- * @private
- * @param {MouseEvent} ev
- */
- _onClickMessageStar: function (ev) {
- var messageID = $(ev.currentTarget).data('message-id');
- this.trigger('toggle_star_status', messageID);
- },
- /**
- * @private
- * @param {MouseEvent} ev
- */
- _onClickMessageModeration: function (ev) {
- var $button = $(ev.currentTarget);
- var messageID = $button.data('message-id');
- var decision = $button.data('decision');
- this.trigger_up('message_moderation', {
- messageID: messageID,
- decision: decision,
- });
- },
- /**
- * @private
- * @param {MouseEvent} ev
- */
- _onClickRedirect: function (ev) {
- // ignore inherited branding
- if ($(ev.target).data('oe-field') !== undefined) {
- return;
- }
- var id = $(ev.target).data('oe-id');
- if (id) {
- ev.preventDefault();
- var model = $(ev.target).data('oe-model');
- var options;
- if (model && (model !== 'mail.channel')) {
- options = {
- model: model,
- id: id
- };
- } else {
- options = { channelID: id };
- }
- this._redirect(options);
- }
- },
- /**
- * @private
- */
- _onClickShowMore: function () {
- this.trigger('load_more_messages');
- },
-});
-
-ThreadWidget.ORDER = ORDER;
-
-return ThreadWidget;
-
-});