summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/js
diff options
context:
space:
mode:
Diffstat (limited to 'addons/mail/static/src/js')
-rw-r--r--addons/mail/static/src/js/activity.js147
-rw-r--r--addons/mail/static/src/js/composer.js2
-rw-r--r--addons/mail/static/src/js/discuss_mobile.js4
-rw-r--r--addons/mail/static/src/js/document_viewer.js35
4 files changed, 120 insertions, 68 deletions
diff --git a/addons/mail/static/src/js/activity.js b/addons/mail/static/src/js/activity.js
index 37903e3861f..4bb81489789 100644
--- a/addons/mail/static/src/js/activity.js
+++ b/addons/mail/static/src/js/activity.js
@@ -2,7 +2,7 @@ odoo.define('mail.Activity', function (require) {
"use strict";
var AbstractField = require('web.AbstractField');
-var concurrency = require('web.concurrency');
+var BasicModel = require('web.BasicModel');
var core = require('web.core');
var field_registry = require('web.field_registry');
var time = require('web.time');
@@ -12,6 +12,63 @@ var QWeb = core.qweb;
var _t = core._t;
/**
+ * Fetches activities and postprocesses them.
+ *
+ * This standalone function performs an RPC, but to do so, it needs an instance
+ * of a widget that implements the _rpc() function.
+ *
+ * @todo i'm not very proud of the widget instance given in arguments, we should
+ * probably try to do it a better way in the future.
+ *
+ * @param {Widget} self a widget instance that can perform RPCs
+ * @param {Array} ids the ids of activities to read
+ * @return {Deferred<Array>} resolved with the activities
+ */
+function _readActivities(self, ids) {
+ if (!ids.length) {
+ return $.when([]);
+ }
+ return self._rpc({
+ model: 'mail.activity',
+ method: 'read',
+ args: [ids],
+ }).then(function (activities) {
+ // convert create_date and date_deadline to moments
+ _.each(activities, function (activity) {
+ activity.create_date = moment(time.auto_str_to_date(activity.create_date));
+ activity.date_deadline = moment(time.auto_str_to_date(activity.date_deadline));
+ });
+
+ // sort activities by due date
+ activities = _.sortBy(activities, 'date_deadline');
+
+ return activities;
+ });
+}
+
+BasicModel.include({
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Fetches the activities displayed by the activity field widget in form
+ * views.
+ *
+ * @private
+ * @param {Object} record - an element from the localData
+ * @param {string} fieldName
+ * @return {Deferred<Array>} resolved with the activities
+ */
+ _fetchSpecialActivity: function (record, fieldName) {
+ var localID = (record._changes && fieldName in record._changes) ?
+ record._changes[fieldName] :
+ record.data[fieldName];
+ return _readActivities(this, this.localData[localID].res_ids);
+ },
+});
+
+/**
* Set the 'label_delay' entry in activity data according to the deadline date
* @param {Array} activities list of activity Object
* @return {Array} : list of modified activity Object
@@ -44,12 +101,6 @@ var setDelayLabel = function(activities){
};
var AbstractActivityField = AbstractField.extend({
- // inherited
- init: function () {
- this._super.apply(this, arguments);
- this.activities = [];
- },
-
// private
_markActivityDone: function (id, feedback) {
return this._rpc({
@@ -59,33 +110,6 @@ var AbstractActivityField = AbstractField.extend({
kwargs: {feedback: feedback},
});
},
- _readActivities: function () {
- var self = this;
- var missing_ids = _.difference(this.value.res_ids, _.pluck(this.activities, 'id'));
- var fetch_def;
- if (missing_ids.length) {
- fetch_def = this._rpc({
- model: 'mail.activity',
- method: 'read',
- args: [missing_ids],
- });
- }
- return $.when(fetch_def).then(function (results) {
- // convert create_date and date_deadline to moments
- _.each(results, function (activity) {
- activity.create_date = moment(time.auto_str_to_date(activity.create_date));
- activity.date_deadline = moment(time.auto_str_to_date(activity.date_deadline));
- });
-
- // filter out activities that are no longer linked to this record
- self.activities = _.filter(self.activities.concat(results || []), function (activity) {
- return _.contains(self.value.res_ids, activity.id);
- });
-
- // sort activities by due date
- self.activities = _.sortBy(self.activities, 'date_deadline');
- });
- },
_scheduleActivity: function (id, previous_activity_type_id, callback) {
var action = {
type: 'ir.actions.act_window',
@@ -116,41 +140,37 @@ var Activity = AbstractActivityField.extend({
'click .o_activity_unlink': '_onUnlinkActivity',
'click .o_activity_done': '_onMarkActivityDone',
},
+ specialData: '_fetchSpecialActivity',
// inherited
init: function () {
this._super.apply(this, arguments);
- this.dp = new concurrency.DropPrevious();
+ this.activities = this.record.specialData[this.name];
},
_render: function () {
- // note: the rendering of this widget is asynchronous as it needs to
- // fetch the details of the linked activities
- var self = this;
- var fetch_def = this.dp.add(this._readActivities());
- return fetch_def.then(function () {
- _.each(self.activities, function (activity) {
- if (activity.note) {
- activity.note = utils.parse_and_transform(activity.note, utils.add_link);
- }
- });
- var activities = setDelayLabel(self.activities);
- if (activities.length) {
- var nbActivities = _.countBy(activities, 'state');
- self.$el.html(QWeb.render('mail.activity_items', {
- activities: activities,
- nbPlannedActivities: nbActivities.planned,
- nbTodayActivities: nbActivities.today,
- nbOverdueActivities: nbActivities.overdue,
- date_format: time.getLangDateFormat(),
- datetime_format: time.getLangDatetimeFormat(),
- }));
- } else {
- self.$el.empty();
+ _.each(this.activities, function (activity) {
+ if (activity.note) {
+ activity.note = utils.parse_and_transform(activity.note, utils.add_link);
}
});
+ var activities = setDelayLabel(this.activities);
+ if (activities.length) {
+ var nbActivities = _.countBy(activities, 'state');
+ this.$el.html(QWeb.render('mail.activity_items', {
+ activities: activities,
+ nbPlannedActivities: nbActivities.planned,
+ nbTodayActivities: nbActivities.today,
+ nbOverdueActivities: nbActivities.overdue,
+ date_format: time.getLangDateFormat(),
+ datetime_format: time.getLangDatetimeFormat(),
+ }));
+ } else {
+ this.$el.empty();
+ }
},
_reset: function (record) {
this._super.apply(this, arguments);
+ this.activities = this.record.specialData[this.name];
// the mail widgets being persistent, one need to update the res_id on reset
this.res_id = record.res_id;
},
@@ -196,9 +216,6 @@ var Activity = AbstractActivityField.extend({
});
return this.do_action(action, {
on_close: function () {
- // remove the edited activity from the array of fetched activities to
- // force a reload of that activity
- self.activities = _.reject(self.activities, {id: activity_id});
self._reload({activity: true, thread: true});
},
});
@@ -312,10 +329,10 @@ var KanbanActivity = AbstractActivityField.extend({
_renderDropdown: function () {
var self = this;
this.$('.o_activity').html(QWeb.render("mail.KanbanActivityLoading"));
- return this._readActivities().then(function () {
+ return _readActivities(this, this.value.res_ids).then(function (activities) {
self.$('.o_activity').html(QWeb.render("mail.KanbanActivityDropdown", {
selection: self.selection,
- records: _.groupBy(setDelayLabel(self.activities), 'state'),
+ records: _.groupBy(setDelayLabel(activities), 'state'),
uid: self.getSession().uid,
}));
});
@@ -328,7 +345,9 @@ var KanbanActivity = AbstractActivityField.extend({
// handlers
_onButtonClicked: function (event) {
event.preventDefault();
- this._renderDropdown();
+ if (!this.$el.hasClass('open')) {
+ this._renderDropdown();
+ }
},
_onMarkActivityDone: function (event) {
event.stopPropagation();
diff --git a/addons/mail/static/src/js/composer.js b/addons/mail/static/src/js/composer.js
index 8de8a242e68..3a7b9c320e1 100644
--- a/addons/mail/static/src/js/composer.js
+++ b/addons/mail/static/src/js/composer.js
@@ -591,7 +591,7 @@ var BasicComposer = Widget.extend({
*/
_onKeydown: function (event) {
switch(event.which) {
- // UP, DOWN: prevent moving cursor if navigation in mention propositions
+ // UP, DOWN, TAB: prevent moving cursor if navigation in mention propositions
case $.ui.keyCode.UP:
case $.ui.keyCode.DOWN:
case $.ui.keyCode.TAB:
diff --git a/addons/mail/static/src/js/discuss_mobile.js b/addons/mail/static/src/js/discuss_mobile.js
index 52622b0ce32..b427ab4b98c 100644
--- a/addons/mail/static/src/js/discuss_mobile.js
+++ b/addons/mail/static/src/js/discuss_mobile.js
@@ -41,7 +41,7 @@ Discuss.include({
*/
on_attach_callback: function () {
if (this.channel && this._isInInboxTab()) {
- this.thread.scroll_to({offset: this.channels_scrolltop[this.channel.id]});
+ this.thread.scroll_to({offset: this.channelsScrolltop[this.channel.id]});
}
},
/**
@@ -49,7 +49,7 @@ Discuss.include({
*/
on_detach_callback: function () {
if (this._isInInboxTab()) {
- this.channels_scrolltop[this.channel.id] = this.thread.get_scrolltop();
+ this.channelsScrolltop[this.channel.id] = this.thread.get_scrolltop();
}
},
diff --git a/addons/mail/static/src/js/document_viewer.js b/addons/mail/static/src/js/document_viewer.js
index 2fa34b613ba..0aac950cf5b 100644
--- a/addons/mail/static/src/js/document_viewer.js
+++ b/addons/mail/static/src/js/document_viewer.js
@@ -17,6 +17,7 @@ var DocumentViewer = Widget.extend({
'click .o_viewer_video': '_onVideoClicked',
'click .move_next': '_onNext',
'click .move_previous': '_onPrevious',
+ 'click .o_rotate': '_onRotate',
'click .o_zoom_in': '_onZoomIn',
'click .o_zoom_out': '_onZoomOut',
'click .o_close_btn, .o_viewer_img_wrapper': '_onClose',
@@ -104,6 +105,30 @@ var DocumentViewer = Widget.extend({
this._reset();
},
/**
+ * Get CSS transform property based on scale and angle
+ *
+ * @private
+ * @param {float} scale
+ * @param {float} angle
+ */
+ _getTransform: function(scale, angle) {
+ return 'scale3d(' + scale + ', ' + scale + ', 1) rotate(' + angle + 'deg)'
+ },
+ /**
+ * Rotate image clockwise by provided angle
+ *
+ * @private
+ * @param {float} angle
+ */
+ _rotate: function (angle) {
+ this._reset();
+ var new_angle = (this.angle || 0) + angle;
+ this.$('.o_viewer_img').css('transform', this._getTransform(this.scale, new_angle));
+ this.$('.o_viewer_img').css('max-width', new_angle % 180 !== 0 ? $(document).height() : '100%');
+ this.$('.o_viewer_img').css('max-height', new_angle % 180 !== 0 ? $(document).width() : '100%');
+ this.angle = new_angle;
+ },
+ /**
* Zoom in/out image by provided scale
*
* @private
@@ -111,7 +136,7 @@ var DocumentViewer = Widget.extend({
*/
_zoom: function (scale) {
if (scale > 0.5) {
- this.$('.o_viewer_img').css('transform', 'scale3d(' + scale + ', ' + scale + ', 1)');
+ this.$('.o_viewer_img').css('transform', this._getTransform(scale, this.angle || 0));
this.scale = scale;
}
},
@@ -284,6 +309,14 @@ var DocumentViewer = Widget.extend({
* @private
* @param {MouseEvent} e
*/
+ _onRotate: function (e) {
+ e.preventDefault();
+ this._rotate(90);
+ },
+ /**
+ * @private
+ * @param {MouseEvent} e
+ */
_onZoomIn: function (e) {
e.preventDefault();
var scale = this.scale + ZOOM_STEP;